cat系関数に数値型を指定の話

あんまり綺麗じゃない、どちかというと外法っぽい小技の紹介です。
以下の2つのデータセットAを作成するコードを見てください。

data A;
X=1;
run;

data A;
X='1';
run;


変数Xが数値型か文字型か、実行時まで確定しないという状況があるとします。
(proc importやlibname excelとかでexcelを読む場合、型が自動判定なので、
まあよくある話です)

そこで、Xが文字型だったらそのままYに代入し、数値型ならbestフォーマットで
文字型に直してYに代入したいという要望があったとします。


まあ

data B;
length Y $200. ;
set A ;
Y = X;
run;


としちゃえば、Xが文字型だろうと数値型だろうといけますが、当然、数値の場合
「NOTE: 以下の箇所で数値を文字値に変換しました。」がでます。
このNOTEをださないようにするにはどうするか。

やってしまいがちなのが以下のような書き方

data B;
set A;
if vtype(X) = 'C' then Y = X ;
else if vtype(X) = 'N' then Y = put(X,best. -L) ;
run;

しかし、これをXが文字型の場合のデータセットAに対して実行すると
ERROR : 出力形式 $BEST が見つからないか、またはロードできません。
となります。else ifステートメントが実行されることはないのですが、
コンパイルの時点で、文字型の変数に数値用のフォーマット充てようとしてるぞバカって
早とちりされてエラーになっちゃいます。

ので、


proc sql noprint;
   select TYPE into: MTYPE
   from DICTIONARY.COLUMNS
   where LIBNAME="WORK" and MEMNAME="A";
quit;

%macro m;
data B;
set A;
%if       &MTYPE = char %then Y = X ;
%else %if &MTYPE = num  %then Y = put(X,best. -L) ;;
run;
%mend m;

%m

のように、一旦Xの型をマクロ変数に格納して(例ではSQL使いましたが方法は何でもいいです)、それによって%ifで
マクロ内で実行されるコードを分岐させるといった方法をとれます。

ですが!!はっきりいって面倒くさい!
型によって実行されるコードが複雑な処理で、厳密に分けたい場合は、上記の感じでいいのですが単純にbestあてて文字にしたいだけなら、以下のような外法もあります


options missing ='';
data B ;
set A;
Y = cats(X,'');
run;
options missing ='.';

cat系関数は、基本文字変数に対する関数ですが、実は数値型の変数を指定すると
自動でbestフォーマットをあてて処理してくれます。暗黙の型変換ではなく関数の
働きによるものなので、結果は同じでもこの場合NOTEがでないんですね。
文字変数だった場合は、ブランクをくっつけているだけなので何もおきません。
なんか、ログを綺麗にするためだけの詐欺みたいな感じですけど。

options missing ='';は、Xが数値変数且つnullだった場合に「.」が文字化されないようにするための一手ですね。

何かほかにいいやり方をお持ちの方は是非教えてください。

まあ、そもそも型がぶれるっていう状況がよくないんですが。



0 件のコメント:

コメントを投稿