2016年5月31日火曜日

【%LET Y=%X】 みたいに書いて指定変数の統計量をマクロ変数に直接格納する方法





SASプログラミング掲示板で過去に以下の質問がありました。
http://tumesas.progoo.com/bbs/tumesas_topic_pr_20.html (サイト閉鎖されたためリンク切れ)


%let Y = %X(データセット, 対象変数 );


みたいな書き方で、「マクロ変数Yに統計量などを格納する事は出来ないか?」 という質問です。
この時、FCMPを使う方法を提案したんですが、もっといい方法を思いついたので、また自己満足のために書き留めておきます。



着想としては以下の記事あたり。
マクロで 【%LET Y=%X】 みたいな書き方
データステップ内でプロシジャを実行する。


以下は、SUMMARYプロシジャを実行して、好きな統計量を直接マクロ変数に落とすマクロです。

*** マクロ登録 ;
%macro m_summary( ds, var, stat );
/********************************************************************
   ds       … 対象データセット
   var      … 対象変数
   stat     … 統計量キーワード
********************************************************************/


/* dosubl関数で値を設定するマクロ変数_mputが既に存在していたら削除 */
/* (削除しないと_mputに正しい値が入らない事があったため) */
%symdel _mput / nowarn;


%local _rc _mput;
%let _rc = %sysfunc(dosubl(%str(


       /* SUMMARYプロシジャを実行 */
       proc summary data=&DS;
          output out=OUT1 &stat(&var)=_mvar1;
       run;

       /* 結果をマクロ変数に格納 */
       /* マクロ変数に数値をいれると、元の値と誤差がでる事があるので注意 */
       data _null_;
          set OUT1;
          call symputx('_mput', _mvar1);
       run;
)));

&_mput

%mend;


*** マクロを実行してみる ;
%let val=%m_summary( sashelp.class, age, mean );
%put &val;


*** データステップでも実行出来るようになってます ;
data DT1;
 VAL1 = %m_summary( sashelp.class, age   , mean );
 VAL2 = %m_summary( sashelp.class, height, mean );
run;



💬 注意事項
プログラム中に青字で書いてるように、dosubl関数内ではマクロ変数が正しく作られない場合があるので、実行後正しい結果が返ってくるか、テストが必要です


また「データステップ100万回」にて紹介されている通り、
マクロ変数に数値をいれると、元の値と誤差がでる事があるので注意。

マクロ変数に数値をいれて戻すと誤差がでちゃう場合がある問題について考える話



実用的かどうかは置いといて、個人的に満足したので良しとします。。
(アイディアの段階のため、この方法を利用する際は、上で記載した問題を考慮する必要があるのと、動作テストも行ったほうが良いです)



2 件のコメント:

  1. うわーっ、驚きです。
    教えていただいたfcmpを用いて、指定データセット/行/変数の値を取得するマクロを作っていたのですが、なんか時々ERRORになるようで、怖くて使用していませんでした。
    dosublなら、もっと安心して使えるマクロになりそうです。ありがとうございました!!!
    ( dosublってどういう語源でしょうか ? do subroutine line ? しっくりこないので覚えにくい )

    返信削除
    返信
    1. ご無沙汰しております!
      私は最近まで考えることをやめて「どすゆーびーえる」とかアホみたいな読み方してましたが、なんなんでしょうかね。
      あとは、do sub line とか?
      scdentさんに言われてみて気になってきました!

      削除