2018年3月5日月曜日

PROC FORMATの「PICTUREステートメント」で気をつけたい内部の動き



PROC FORMATのPICTUREステートメントはちゃんと内部挙動を理解しないと痛い目を見ます。
動きが独特なので、しっかり理解できてる人はSASマイスターとして認定してもいいくらいです。


※今回の内部挙動に関する説明は私の推測も入ってるのであしからず。。間違いがあったらご指摘ください。




PICTUREステートメントの動き

以下のフォーマットを例に内部の動きを説明していきます。

proc format;
   picture TEST1_
       0 - 100 = '009.00%';
run;


① まず、フォーマットをあてる変数に10のn乗を掛けます。(n = 定義した書式の小数点以下桁数)

今回定義した書式は '009.00%' です。小数点以下桁数は2桁で定義されてますよね。
なのでフォーマットをあてる変数に10の2乗を掛けます。


1.23 → 123
3.456 → 345.6
(小数点以下2桁部分を整数部分にシフトさせている。)


②結果から小数部分を切り捨てます。
123 → 123
345.6 → 345


③この値を、定義した書式に右からあてはめていきます。

'009.00%' の数字セレクタ部分に右から数値をあてはめると、
123 → 001.23% →「  1.23%」
345 → 003.45% →「  3.45%」





「ROUND」「MULTIPLIER」オプションの動き


以下のフォーマットを例に内部の動きを説明していきます。

proc format;
   picture TEST2_ (round)
      0 - 100 = '009.00%' (multiplier=10) ;
run;


①まず、フォーマットをあてる変数には10のn乗を掛けずに、multiplier=オプションに設定した数を掛けます。


今回は「multiplier=10」なので
1.23 → 12.3
3.456 → 34.56


②roundオプションを指定している場合、小数部分を切り捨てではなく四捨五入します。

12.3 → 12
34.56 → 35


③この値を、定義した書式に右からあてはめていきます。

'009.00%' の数字セレクタ部分に右から数値をあてはめると、
12 → 000.12% →「  0.12%」
35 → 000.35% →「  0.35%」



実践


例えば、以下の変数Xには何かの割合が格納されているとします。

data DT1;
   input X;
   cards;
0.123
1
0.456
0.6789
;
run;

X
 0.123 
 1 
 0.456 
 0.6789 


このXを「0.123 → '12.3%'」 のように百分率にした上で%をつけたいとします。
今回解説した内容を踏まえると以下のようになるかと思います。

proc format;
   picture TEST3_ (round)
      0 - 1 = "009.0%" (multiplier=1000);
run;

data DT2;
   set DT1;
   length PCT $30.;
   PCT = put(x,TEST3_.);
run;

X 
 PCT 
 0.123
  12.3% 
 1 
 100.0%
 0.456
  45.6%
 0.6789 
  67.9%



厄介なケース


内部で10のn乗とか計算してることによって、小数点誤差が発生する可能性があります。

「小数点誤差?」って人は以下参照
http://sas-tumesas.blogspot.jp/2014/03/blog-post_14.html(データステップ100万回)


小数点誤差が問題になる例
proc format;
    picture TEST4_
       0 - 999 = '009.000000000' ;
run;

data DT3;
    X = 2.01;
    length Y $30.;
    Y = put(X,TEST4_.);
run;

X 
 Y 
 2.01 
   2.009999999 

「2.01」が「  2.00999…」となってしまいます。


以下のようにROUNDオプションで四捨五入しとけば一応は「2.01」と表示されますが、、

proc format;
    picture TEST4_ (round)
       0 - 999 = '009.000000000';
run;

data DT3;
    X = 2.01;
    length Y $30.;
    Y = put(X,TEST4_.);
run;

X 
 Y 
 2.01 
   2.010000000 

以下の最後の方で説明している通り、ROUNDしとけばOKというわけでもないのでご注意下さい。
http://sas-boubi.blogspot.jp/2016/03/put-floating-point-error.html


0 件のコメント:

コメントを投稿