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】 みたいに書いて指定変数の統計量をマクロ変数に直接格納する方法


2016年5月13日金曜日

マクロ言語入門4:パラメータの設定【キーワードパラメータ】



マクロに「キーワードパラメータ」というものを設定する方法を紹介します。





基本構文


マクロの登録
%MACRO  マクロ名( マクロ変数1=, マクロ変数2= ・・・ );

   ~プログラム~

%MEND;

  • 同名のマクロを同じ場所(カタログ)に複数作成することはできないので注意(上書きされる)
  • まず「%MACRO;」~「%MEND;」の中にマクロとして登録したいプログラムを書きます。
  • マクロ内で使用したいマクロ変数を「マクロ名」のカッコ内に列挙しておきます。




上記「マクロ名」のカッコ内に列挙したマクロ変数に対し、以下のように値を設定してマクロを実行します。

マクロの実行
%マクロ名( マクロ変数1=値, マクロ変数2=値 ・・・ )

  • マクロ変数に設定する値の両端に半角スペースを入れても、それらスペースはマクロ変数に含められません(別記事で解説する%STR関数を使用して含めることも可)
  • また、実行時「このマクロ名はNG」「このステートメントはマクロではNG」などのマクロのルールに違反している旨のログメッセージがないかも要確認です。




簡単な例

*** マクロ登録 ;
%macro TEST( DS= );
     proc print data=&DS;
     run;
%mend;

*** マクロ実行 ;
%TEST( DS=SASHELP.CLASS )
;


最終的に以下のプログラムが展開・実行されます。
proc print data=SASHELP.CLASS;
run;




パラメータに初期値を与える

*** マクロ登録 ;
%macro TEST( DS=SASHELP.CLASS );
     proc print data=&DS;
     run;
%mend;

*** マクロ実行 ;

%TEST();
%TEST(DS=SASHELP.IRIS);
%TEST(DS=SASHELP.RETAIL);



%macro TEST( DS=SASHELP.CLASS )」 で TESTマクロのマクロ変数DSに SASHELP.CLASS という初期値を与えています。


よってこのマクロを実行する際、

  • %TEST()」 でマクロ変数DS への値を指定しないと初期値 SASHELP.CLASS が使われて実行。
  • %TEST(DS=SASHELP.IRIS)」 でマクロ変数DS の値を SASHELP.IRIS に上書きして実行。
  • %TEST(DS=SASHELP.RETAIL)」 でマクロ変数DS の値を SASHELP.RETAIL に上書きして実行。

という動きをします。




記事一覧

1. マクロ変数とは
2. マクロの登録と実行
3. 定位置パラメータ
4. キーワードパラメータ
5. クォート処理
6. クォート処理2
7. ループ処理
8. 条件分岐処理
9. ドット
10. &&
11. 演算評価
12. 補足


2016年5月12日木曜日

マクロ言語入門3:パラメータの設定【定位置パラメータ】



マクロに「定位置パラメータ」というものを設定する方法を紹介します。





基本構文



マクロの登録
%MACRO  マクロ名( マクロ変数1, マクロ変数2 ・・・ );

   ~プログラム~

%MEND;

  • 同名のマクロを同じ場所(カタログ)に複数作成することは出来ないので注意(上書きされる)
  • 「%MACRO」~「%MEND;」の中にマクロとして登録したいプログラムを書きます。
  • マクロ内で使用したいマクロ変数を「マクロ名」のカッコ内に列挙しておきます。




上記「マクロ名」のカッコ内に列挙したマクロ変数に対し、以下のように値を設定してマクロを実行します。

マクロの実行
%マクロ名( マクロ変数値1, マクロ変数値2 ・・・ )

  • マクロ変数値の両端に半角スペースを入れても、それらスペースはマクロ変数に含められません(別記事で解説する%STR関数を使用して含めることも可)
  • また、実行時「このマクロ名はNG」「このステートメントはマクロではNG」などのマクロのルールに違反している旨のログメッセージがないかも要確認です。






*** マクロ登録 ;
%macro TEST( DS );
     proc print data=&DS;
     run;
%mend;

*** マクロ実行 ;
%TEST( SASHELP.CLASS )
;

  • %macro TEST( DS )」 で「TESTマクロにDSというマクロ変数があるよ」と教えておく。
  • %TEST( SASHELP.CLASS )」でマクロ変数DS に SASHELP.CLASS という値を当てはめて実行。


最終的に以下のプログラムが展開・実行されます。

proc print data=SASHELP.CLASS;
run;




記事一覧

1. マクロ変数とは
2. マクロの登録と実行
3. 定位置パラメータ
4. キーワードパラメータ
5. クォート処理
6. クォート処理2
7. ループ処理
8. 条件分岐処理
9. ドット
10. &&
11. 演算評価
12. 補足


2016年5月11日水曜日

マクロ言語入門2:マクロの登録と実行【%MACRO、%MEND】





データセットあるいは変数を変えて同じような処理を繰り返し実行したい場合、マクロを使うと便利です。
まずは基本構文から触れてみましょう。




基本構文



マクロの登録
%MACRO  マクロ名;

   ~プログラム~

%MEND;

  • 同名のマクロを同じ場所(カタログ)に複数作成することは出来ないので注意(上書きされる)
  • 「%MACRO」~「%MEND;」の中にマクロとして登録したいプログラムを書きます。



マクロの実行
%マクロ名

  • 登録したマクロを「%マクロ名」で実行する事が出来ます。
  • 実行時、「このマクロ名はNG」「このステートメントはマクロではNG」などのマクロのルールに違反している旨のログメッセージがないかも要確認です。




例①

*** マクロの登録 ;
%macro TEST;
   proc print data=SASHELP.CLASS;
   run;
%mend;

PRINTプロシジャでデータセットSASHELP.CLASSを出力するマクロTESTを登録しています。
このプログラムでマクロTESTは登録されますが、まだマクロの中身のプログラムは実行されません。



* マクロの実行 ;
%TEST;

マクロTESTを実行。
これにより先に登録しておいたマクロTESTの中身のプログラムが実行されます。


ちなみに、マクロの中にマクロを入れ込む事も出来ます。詳細は以下記事を参照ください。
マクロ実行文をログに展開するMPRINTとMPRINTNEST




例②

*** マクロ登録 ;
%macro TEST;
   proc print data=&DS;
   run;
%mend;

*** マクロ実行 ;
%let DS = SASHELP.CLASS;
%TEST;

%let DS = SASHELP.IRIS;
%TEST;

PRINTプロシジャでデータセットを出力するマクロTESTを登録。
「proc print data=&DS」 というように出力対象のデータセットを 「&DS」 とマクロ変数化しています。

これにより、以下のように%LETステートメントで出力するデータセットを変更しながらマクロを繰り返し実行することが出来ます。

%let DS = 出力対象のデータセット;
%TEST;






2016年5月10日火曜日

マクロ言語入門1:マクロ変数とは【%LET】



マクロの入門記事を書いていきます。まずは基本の「マクロ変数」について解説。





マクロ変数とは?


以下のプログラムを見てください。

proc print data=SASHELP.CLASS;
run;

proc means data=SASHELP.CLASS;
run;

proc contents data=SASHELP.CLASS;
run;


データセットSASHELP.CLASSに対して、PRINT, MEANS, CONTENTSプロシジャを実行しています。
ここで 「SASHELP.CLASS」 を何回も書くのが面倒なのでマクロ変数を使って以下のように書き換えてみます。

%let DS = SASHELP.CLASS ;

proc print data=&DS;
run;

proc means data=&DS;
run;

proc contents data=&DS;
run;



解説
%let DS = SASHELP.CLASS ;

「DS」という名前で定義した入れ物に「SASHELP.CLASS」という値を入れています。
この入れ物を 「マクロ変数」 と呼びます。


マクロ変数に値を設定する構文は「%LET マクロ変数 = 格納値;」となっていて、

  • このステートメントで格納値の両端に半角スペースを入れても、それらスペースはマクロ変数に含められない(別記事で解説する%STR関数を使用して含めることも可)
  • SAS側で定義している「自動マクロ変数」というものもあって、それらと同じ名前のマクロ変数を定義しないよう注意(どんな自動マクロ変数があるかはリファレンスを参照)
  • 格納値に入れると挙動が変わってしまうマクロ特有の文字(&,%等)が存在。マクロを理解するとその辺りも分かってくると思います。


proc print data=&DS;
run;

プログラム中で 「&DS」 というように&をくっつけたものはマクロ変数として解釈されます。
よって「proc print data=&DS;」は「proc print data=SASHELP.CLASS;」に置き換えて実行されます。




マクロ変数を使う利点


便利なのが、対象のデータセットをSASHELP.IRISに変えて再実行したい場合、先頭のプログラムを変えるだけで済みます。

%let DS = SASHELP.IRIS ;

proc print data=&DS;
run;

proc means data=&DS;
run;

proc contents data=&DS;
run;




マクロ変数値の確認方法


%PUT &マクロ変数名;」 でマクロ変数値をログに出力する事が出来ます。

%let DS = SASHELP.IRIS ;
%put &DS;

ログ
SASHELP.IRIS





記事一覧

1. マクロ変数とは
2. マクロの登録と実行
3. 定位置パラメータ
4. キーワードパラメータ
5. クォート処理
6. クォート処理2
7. ループ処理
8. 条件分岐処理
9. ドット
10. &&
11. 演算評価
12. 補足

2016年5月9日月曜日

マクロで 【%LET Y=%X】 みたいな書き方


あんまりやらない書き方かもしれないですが、覚えとくと役に立つと思います。


例①

%macro X;
   aaa
%mend;

%let Y = %X;

上のプログラムで、マクロ変数Yに入る値はなんでしょうか?

答え
%put &Y;

ログ
aaa

これは分かり易いと思います。


例②

%macro X;

   %local A B C;
   %let A=aaa;
   %let B=bbb;
   %let C=&A&B;

   &C

%mend;

%let Y = %X;

マクロ変数Yに入る値はなんでしょうか?

答え
%put &Y;

ログ
aaabbb

マクロ変数AとBをくっけた値「aaabbb」が返されます。
プログラム青字部分が加工フェーズ、赤字部分が展開フェーズ、みたいな構造になっています。


細かい動きは、マクロプロセッサというものを理解する必要があって、
詳しくはリファレンスを見ていただきたいのですが、

マクロ中の %LOCAL, %GLOBAL, %LET の文は、マクロプロセッサが絡むおかげで今回のような書き方が出来ると思ってください。
なので、マクロプロセッサの手中におさめられないような処理(データステップやプロシジャ等)を含めてしまうと、今回の「%let Y=%X」みたいな使用方法は出来なくなります。


この動きを理解することで、今回のような関数みたいなマクロを作ることが出来ます。


2016年5月7日土曜日

箱ひげ図をかく 【SGPLOT編】




構文

箱ひげ図の向きによってステートメントが分かれます。


縦向き
  PROC SGPLOT DATA=対象データセット;
      VBOX  分析変数 / CATEGORY=カテゴリ  オプション ;
  RUN;


横向き
  PROC SGPLOT DATA=対象データセット;
      HBOX  分析変数 / CATEGORY=カテゴリ  オプション ;
  RUN;

  • デフォルトで「CATEGORY=」を指定した軸は離散軸になりますが、ユーザー側で線形軸等に変えると、挙動が変わってしまいます。詳細はリファレンスを要確認。



オプション
  設定内容  指定   詳細設定
  箱の幅

  BOXWIDTH  =  0~1

  
  箱の書式

  FILLATTRS  =  (詳細設定) 

  COLOR = 色

  ひげの書式

  WHISKERATTRS  =  (詳細設定) 

  COLOR = 色

  中央値の書式

  MEDIANATTRS  =  (詳細設定)

  COLOR = 色

  平均値の書式 

  MEANATTRS  =  (詳細設定)
  
  COLOR   = 色
  SYMBOL = 表示マーク  

  外れ値の書式 

  OUTLIERATTRS  =  (詳細設定)   

  SYMBOL = 表示マーク 
  

…etc ( 色々できるのでリファレンスを確認してみてください )



注意
  • オプションの組み合わせで挙動が変わる可能性あり。
  • デフォルトで出力される箱ひげ図のタイプ(箱、ひげ、外れ値等の定義)はリファレンスを要確認



1. 簡単な例


title "お魚の体重分布";
proc sgplot data=SASHELP.FISH;
   vbox WEIGHT / category=SPECIES;
run;




2.カスタマイズ

title "お魚の体重分布";
proc sgplot data=SASHELP.FISH;
   hbox WEIGHT / category=SPECIES
                         boxwidth = 0.3
                         meanattrs = (color=black symbol=plus)
                         fillattrs = (color=white)
                         whiskerattrs = (color=black)
                         medianattrs = (color=black)
                         outlierattrs = (symbol=circlefilled);
run;