ラベル 関数: DOSUBL の投稿を表示しています。 すべての投稿を表示
ラベル 関数: DOSUBL の投稿を表示しています。 すべての投稿を表示

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万回」にて紹介されている通り、
マクロ変数に数値をいれると、元の値と誤差がでる事があるので注意。

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



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



2016年5月17日火曜日

データステップ内でプロシジャを実行する。



SASで遊んでる時に作ったマクロを自己満足のために載せたいと思います。


データステップ内でSUMMARYプロシジャ実行して、好きな統計量を変数に落とすマクロです。
以下「僕の頁」で紹介されているDOSUBL(SAS9.3以上)とFETCHOBSを使いました。

・dosubl関数(call executeの兄弟)
・fetchobs関数

*** マクロ登録 ;
%macro m_summary( ds, var, stat, newvar );
************************************;
* ds       … 対象データセット ;
* var      … 対象変数 ;
* stat     … 統計量キーワード ;
* newvar … 結果を格納する変数 ;
************************************;

   *** SUMMARYプロシジャを実行 ;
   _rc = dosubl("

       proc summary data=&ds;
          output out=_sumout1 &stat(&var)=_mvar1;
       run;

   ");

   *** 結果を取得 ;
   length _mvar1 8.;
   _mvar1=.;

   _dsid = open("_sumout1(keep=_mvar1)") ;
   call set(_dsid);
   _rc = fetchobs(_dsid,1);
   _rc = close(_dsid);

   &newvar = _mvar1;

   *** マクロ内で作った一時変数を削除 ;
   drop _rc _dsid _mvar1;

%mend;



*** データステップ内でマクロを実行してみる ;
data dt1;
   length avg_age avg_hei 8.;
   %m_summary( sashelp.class, age, mean, avg_age );
   %m_summary( sashelp.class, height, mean, avg_hei );
run;
 avg_age
avg_hei
 13.315789474  
  62.336842105 

※本マクロは粗削りな部分があるので、ご利用される場合は、マクロの内容を理解頂いて、適宜中身を修正ください。


ポイント
以下「データステップ100万回」で紹介されている通り、
マクロ変数に数値をいれると、元の値と誤差がでる事があるので、結果を取得する部分ではマクロ機能の使用を避けて、OPEN, FETCHOBS関数を使用してみました。

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



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