2018年1月31日水曜日

INFORMATの落とし穴【デフォルト長】



以下のプログラムと結果をご覧ください。結果は想定通りでしょうか?

proc format;
    invalue MYFMT
    "abc"   = 1
    ;
run;

data DT1;
    X = "abcdefg";
    Y = input( X , MYFMT. );
run;
  X    Y  
  abcdefg   1 


変数Y が 1 という結果はおかしいですよね。これって

・INFORMATの値   …  "abc"
・変数X の値           …  "abcdefg"

といった感じで、値が一致してないのに、一致してるかのように変換が行われています。




原因

これは、INFORMATの「デフォルト長 (Default Length)」というものが関係してます。
例えば、今回の例では、、

proc format;
    invalue MYFMT
    "abc"   = 1
    ;
run;


定義した値 "abc" の文字の長さは3バイトです。
この長さが、そのINFORMATの「デフォルト長」というものになります。
(定義した値が複数ある場合は、文字の長さが最も大きいものがそのINFORMATの「デフォルト長」になる)



そしてこのINFORMATは、以降の処理でデフォルト長となった3バイトしか視界に入らなくなります。
どういう事かというと、、

data DT1;
    X = "abcdefg";
    Y = input( X , MYFMT. );
run;


変数X の値 "abcdefg" から先頭の3バイトの値 "abc" だけを見てINFORMATによる変換が行われるという事です。


ちょうど PROC FORMAT で"abc" を定義してたので、変換しちゃったってわけですね。

proc format;
    invalue MYFMT
    "abc"   = 1
    ;
run;



解決策


変数X の値 "abcdefg" の文字の長さは7バイトなので、7バイト全部読み込んで変換する必要があります。
解決策としては以下の2つの方法があります。


解決策①

proc format;
    invalue MYFMT (default=7)
      "abc"   = 1
    ;
run;

data DT1;
    X = "abcdefg";
    Y = input( X, MYFMT. );
run;
   Y  
  abcdefg   . 

「DEFAULT=オプション」によってこのINFORMATのデフォルト長を 7 に広げています。


解決策②

proc format;
    invalue MYFMT
      "abc"   = 1
    ;
run;

data DT1;
    X = "abcdefg";
    Y = input( X, MYFMT7. );
run;
   Y  
  abcdefg   . 

INPUT関数による変換時に、INFORMAT名の後ろに読み込む幅を指定することも出来ます。


0 件のコメント:

コメントを投稿