2015年9月27日日曜日

Graph Template Language(GTL)入門:関数



GTLの中で関数を使う方法を紹介したいと思います。



GTLで使える関数


  •  SAS関数
    • データステップで使用している関数(ただしLAG関数などデータステップに特化した関数など一部使えないのもある)
    • GTL内で使えるSAS関数でも、一部機能がGTL内ではうまく動作しないこともあるようなので、使用時は挙動を要確認。

  •  GTL専用の関数
    • 話が込み入ってしまうので今回は割愛。

  •  集計関数
    • MEAN, MIN, MAX, MEDIAN...等の集計関数が用意されてます(使用できる集計関数はSAS社のリファレンスを参照下さい)


ルール

上記関数を使用するにはEVAL関数で囲む必要があります。

EVAL( 使用したい関数 )





* グラフテンプレート作成 ;
proc template;
  define statgraph MYGRAPH;
  begingraph;
       layout overlay;
             scatterplot x=HEIGHT y=WEIGHT;
             referenceline x=eval( mean(HEIGHT) ) / curvelabel="x平均";
             referenceline y=eval( mean(WEIGHT) ) / curvelabel="y平均";
endlayout;
entryfootnote "作成日時:" eval( put(datetime(),datetime.) ) ;
  endgraph;
  end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH;
run;





解説

referenceline x=eval( mean(HEIGHT) ) / curvelabel="x平均";
referenceline y=eval( mean(WEIGHT) ) / curvelabel="y平均";

REFERENCELINEステートメントで参照線を引いていますが、
  • x=eval(mean(HEIGHT)) でHEIGHTの平均値を計算して、この平均値を参照線としてX軸にひいてます。
  • 同様にy=eval(mean(WEIGHT)) でWEIGHTの平均値を参照線としてY軸にひいてます。


entryfootnote "作成日時:" eval( put(datetime(),datetime.) ) ;

DATETIME関数とPUT関数で実行日時をフッターに表示してます。



関数
マクロ変数を引数にする

2015年9月24日木曜日

「input @@」で外部ファイルの同じ行を読み続ける。



以下のようなCSVファイルがあったとします。

C:\TEST\SAMPLE.csv
aa,10,bb,20,cc,30
dd,40,ee,50


これを読み込んで以下のSASデータセットを作成したいとします。
 V1 
 V2 
  aa  
  10  
  bb  
  20  
  cc 
  30  
  dd  
  40  
  ee  
  50  


これはINPUTステートメントの最後に「@@」を追加してあげればok。
data DT1;
    length V1 $10. V2 8.;
    infile "C:\TEST\SAMPLE.csv" dlm="," dsd lrecl=32767;
    input V1 V2 @@;
run;


「@@」を入れることで、CSVファイルの同じ行を繰り返し読みに行くことができます。
読みにいくデータがなくなったら次の行に移動して、またその行を繰り返し読みに行く感じです。


2015年9月19日土曜日

データステップ外で関数を使えるようにする「%SYSFUNC」その2




その1」 のおまけ。
%SYSFUNCで、PUT関数とかINPUT関数を使ったらエラーでたんだけど。。」という質問をもらう事があります。



試してみる。

proc format;
   value  FMT_
   1="aa"
   2="bb"
   ;
run;

%put %sysfunc( put(2,FMT_) );

ログ
ERROR: %SYSFUNC または %QSYSFUNC マクロ関数で参照されている PUT 関数がありません。



確かにエラーが出ます。
実は%SYSFUNCでは、PUT / INPUT関数がサポートされていません。
代わりに、PUTN / PUTC / INPUTN / INPUTC関数 がサポートされてるので、これらで代用できます。

%put %sysfunc( putn(2,FMT_) );

ログ
bb



PUTN関数などは、SASYAMAさんが解説をされています。

データステップでは 「putn(2, "FMT_")」 というように書きますが、%SYSFUNCでは文字列を引用符(クオーテーション)で囲む必要がないので、「putn(2, FMT_)」 と書きます(前回の記事参照)




おまけ

%SYSFUNC関数の小技

2015年9月16日水曜日

データステップ外で関数を使えるようにする「%SYSFUNC」その1




%SYSFUNCは、SAS関数やFCMPで定義した関数を、データステップ外で使えるようにしてくれます。
構文は簡単で、使用したい関数を%SYSFUNCで囲むだけ。



構文

%SYSFUNC(  関数  )







データステップ外でSUBSTR関数を使って文字の抽出を行い、ログに出力する例

%put %sysfunc( substr(ABCDE, 2, 3) );

---ログ---
BCD


%let MAC= ABCDE;
%put %sysfunc( substr(&MAC, 2, 3) );

---ログ---
BCD


ポイント
・全ての関数や関数の機能がサポートされてるわけではない。

・文字列を引用符(クオーテーション)で囲む必要がない。
例えば、データステップでは 「SUBSTR("ABCDE", 2, 3)」 というように文字列に引用符を付ける必要がありますが、上の例のように 「SUBSTR(ABCDE, 2, 3)」 と引用符は不要です。




落とし穴


以下の例はエラーが出てうまくいきません。

%let MAC= AB,CDE;
%put %sysfunc( substr(&MAC,2,3) );

ログ
ERROR: %SYSFUNC または %QSYSFUNC マクロ関数で参照されている関数 SUBSTR にある引数は多すぎます。


まず、マクロ変数MACが展開されると、、
%sysfunc( substr(&MAC,2,3) )

以下のようになります。
%sysfunc( substr(AB,CDE,2,3) )

この展開された文字にカンマが含まれてるのが問題で、
SUBSTR関数の中の第1引数が「AB」、第2引数が「CDE」、第3引数が「2」、第4引数が「3」と解釈されちゃってエラーが起きたわけです。



解決法


%BQUOTE関数などのマスク機能を持ったマクロ関数で囲んで、「AB,CDE」の中のカンマを無効化してあげます。

%let MAC= AB,CDE;
%put %sysfunc( substr(%bquote(&MAC),2,3) );

ログ
B,C

%BQUOTE関数ついては以下記事で解説しています
マクロ言語入門6:クォート処理【%BQUOTE関数】



その他注意

以下、データステップ100万回で取り上げられていますが、マクロ変数に結果をいれることで、誤差が出てしまうようなのでご注意下さい。

データステップ100万回 「マクロ変数に数値をいれて戻すと誤差がでちゃう場合がある問題について考える話



その2につづく。。

2015年9月15日火曜日

三角関数で星印を描画する


いろいろな関数を使ってみたかっただけの記事です。
やってることは三角関数つかって座標求めてSGPLOTで星を描画してるだけです。

*** 描画用データ作成 *********;
data DT1;
   * 星の中心のx軸とy軸の座標 ;
   x0 = 100;
   y0 = 100;

   * 星の中心からの半径 ;
   r  = 50;

   * 1辺の角度 ;
   degree = 360/5;

   * ラジアン変換用 ;
   rad = constant('pi')/180;

   * 星のかどの座標を取得 (90度からスタート) ;
   do i=0 to 10 by 2;
      x = x0 + cos((90+i*degree)*rad) * r;
      y = y0 + sin((90+i*degree)*rad) * r;
      output;
   end;
run;


*** 星描画 ******************;
proc sgplot data=DT1;
   series x=X y=Y;
   xaxis min=0 max=200;
   yaxis min=0 max=200;
run;


使用してる関数は以下の通り。

CONSTANT … 指定した数学定数を返す。 ('pi'で円周率を返す)
COS  … コサインを返す。 (角度をラジアン変換した数値を指定する)
SIN   … サインを返す。 (角度をラジアン変換した数値を指定する)



2015年9月11日金曜日

ODSグラフ(SG系グラフ)を、画像ファイルとして保存する方法



🔎 重要
  • 一部のODS出力(ODS HTML, ODS EXCEL等)が開いていると、保存する画像ファイル名がおかしくなることがあるので、それらは最初にCLOSEしておくこと(理由は最後のリンク記事を参照)
  • 以下「outputfmt」はSAS9.2では「imagefmt」に変更する必要あり




ods html close;   /* ←他に開いているODS出力先があればCLOSEして下さい */

ods graphics  /  reset=index  imagename="SAMPLE"  outputfmt=png;
ods listing gpath="C:\TEST";

     proc sgplot data=SASHELP.CLASS;
        scatter x=HEIGHT y=WEIGHT;
     run;

ods listing close;
ods graphics  /  reset=all;

ods html;      /* ←デフォルトの出力をHTMLにしている場合に記述  */
ods listing;    /* ←デフォルトの出力をLISTINGにしている場合に記述  */
/* その他、デフォルトの出力があれば、適宜記述 */


SAMPLE.png





構文と解説


ODS GRAPHICSのオプション

reset = リセットする設定
imagename = "ファイル名"
outputfmt = ファイル種類 (jpg, png等) ※SAS9.2ではオプション名をimagefmtに要変更


ODS LISTINGのオプション

gpath = "ファイルパス";


プログラム中の最初のほうの「reset=index」と最後のほうの「ods graphics  /  reset=all;」を消して何回か実行してみてください。

最初に実行すると 「SAMPLE.png」 が作成されますが、繰り返し実行する度に 「SAMPLE1.png」「SAMPLE2.png」 というように連番が振られた別ファイルが作られてしまいます。

この連番をリセットするのが「reset=index」です。
また最後に「reset=all」で、ODS GRAPHICSの設定を全てリセットしています。




注意事項

ODSグラフ(SG系グラフ)保存時の落とし穴

2015年9月7日月曜日

Graph Template Language(GTL)入門:DYNAMICステートメント【引数の設定】


DYNAMICステートメントを使うと、マクロや関数みたいに引数を設定できます。


構文


PROC TEMPLATE;
    DEFINE STATGRAPH  テンプレート名;
              DYNAMIC  ダイナミック変数1  ダイナミック変数2 ・・・ ;

              ~ ここにダイナミック変数を使ってグラフを作成する文を書く ~
    END;
RUN;



PROC SGRENDER  DATA=プロットするデータセット  TEMPLATE=テンプレート名;
    DYNAMIC  ダイナミック変数1=設定値  ダイナミック変数2=設定値 ・・・; 
RUN;


構文だけだとよく分かんないので例を見てみましょう。

(ちなみに「ダイナミック変数の設定値に対して、クォーテーションをつけるか否か」が間違えやすいです。その点も記事の最後に解説してるのでご参照下さい)





* グラフテンプレート作成 ;
proc template ;
    define statgraph MYGRAPH;
        dynamic _XVAR _YVAR;
        begingraph ;
           layout overlay ;
               scatterplot  x=_XVAR  y=_YVAR;
           endlayout;
        endgraph;
    end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH;
    dynamic  _XVAR="WEIGHT"  _YVAR="HEIGHT";
run;



解説

proc template ;
    define statgraph MYGRAPH;
        dynamic _XVAR _YVAR;

① まずはTEMPLATEプロシジャにて「dynamic _XVAR _YVAR;」で 「_XVAR」「_YVAR」 というダイナミック変数を定義。


        begingraph ;
           layout overlay ;
               scatterplot  x=_XVAR  y=_YVAR;
           endlayout;
        endgraph;
    end;
run;

② 「scatterplot  x=_XVAR  y=_YVAR;」で、X軸とY軸を①で定義したダイナミック変数で仮設定しておく。


proc sgrender data=SASHELP.CLASS template=MYGRAPH;
    dynamic  _XVAR="WEIGHT"  _YVAR="HEIGHT";
run;

③ SGRENDERでグラフ作成を実行する際に、「dynamic _XVAR="WEIGHT" _YVAR="HEIGHT";」でTEMPLATEプロシジャ内の、
  • ダイナミック変数「_XVAR」を「WEIGHT」に、
  • ダイナミック変数「_YVAR」を「HEIGHT」に設定して実行します。



利点

以下のように、ダイナミック変数の設定値を変えて再度実行する事が出来るので、汎用性が高いTEMPLATEが作れます。

proc sgrender data=SASHELP.CLASS template=MYGRAPH;
    dynamic  _XVAR="AGE"  _YVAR="HEIGHT";
run;




覚えておきたいポイント


ポイント1

「ダイナミック変数」と「PLOTに使用するデータセットの変数」の名前が被らないようにご注意下さい。挙動がおかしくなります。



ポイント2

「ダイナミック変数の設定値に対して、クォーテーションをつけるか否か」のルールとして、
  • 変数名や文字に対してはクォーテーションをつける
  • 数値の場合、
    • 「10」のように数値1個だけの設定値の場合はクォーテーションをつけない
    • 「10 20 30」のような数値を列挙するような設定値の場合はクォーテーションをつける

以下、上のルールを適用した例

* グラフテンプレート作成 ;
proc template ;
    define statgraph MYGRAPH;
        dynamic _ETITLE _XMIN _XMAX _XLIST _XVAR _YVAR;
        begingraph ;
           entrytitle _ETITLE;
           layout overlay / xaxisopts=(linearopts=(
                                        viewmin=_XMIN viewmax=_XMAX tickvaluelist=_XLIST));
                scatterplot  x=_XVAR  y=_YVAR;
           endlayout;
        endgraph;
    end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH;
    dynamic _ETITLE = "散布図"
                 _XMIN = 0
                 _XMAX = 200
                 _XLIST = "0 100 200"
                 _XVAR = "WEIGHT"
                 _YVAR = "HEIGHT";
run;


特に「TICKVALUELIST」に注目!
PROC TEMPLATEでは通常、以下のようにカッコで囲って数値を列挙しますが、

tickvaluelist=(0 100 200)


ダイナミック変数を使う場合、カッコは不要

tickvaluelist=_XLIST


また、PROC SGRENDERでダイナミック変数に設定する値はクォーテーションで囲ってあげないと認識してくれません。

_XLIST="0 100 200"


このように「カッコをつけるか否か」や「クォーテーションをつけるか否か」など、細かいルールでミスってうまく動かないことが多いので、リファレンスを参照しつつ、実行後にログや出力結果を確認するようにしましょう。


引数の設定

2015年9月1日火曜日

Graph Template Language(GTL)入門:LAYOUTステートメント【LATTICE】【GRIDDED】



LAYOUT LATTICE

LAYOUT LATTICEの中にPLOTステートメントを複数書いて左右上下に並べる事ができます。


構文
  LAYOUT LATTICE  /  ROWS=行数  COLUMNS=列数  ORDER=配置順;
       PLOTステートメント;
  ENDLAYOUT;


① まず簡単な例

* グラフテンプレート作成 ;
proc template ;
  define statgraph MYGRAPH1;
      begingraph ;
          layout lattice;
              boxplot x=AGE y=HEIGHT;
              boxplot x=AGE y=WEIGHT;
          endlayout;
      endgraph;
  end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH1;
run;



② 左右上下に並べる

* グラフテンプレート作成 ;
proc template ;
  define statgraph MYGRAPH2;
      begingraph ;
          layout lattice / rows=2 columns=2 ;
              boxplot x=AGE y=HEIGHT;
              boxplot x=AGE y=WEIGHT;
              scatterplot x=WEIGHT y=HEIGHT;
          endlayout;
      endgraph;
  end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH2;
run;


③ PLOTの配置順を設定する

ORDER=オプションで配置順を設定します。

ORDER=ROWMAJOR ・・・ 横方向に配置していく (デフォルト設定)

ORDER=COLUMNMAJOR ・・・ 縦方向に配置していく

縦方向に配置していく例
* グラフテンプレート作成 ;
proc template ;
  define statgraph MYGRAPH3;
      begingraph ;
          layout lattice / rows=2 columns=2 order=columnmajor;
              boxplot x=AGE y=HEIGHT;
              boxplot x=AGE y=WEIGHT;
              scatterplot x=WEIGHT y=HEIGHT;
          endlayout;
      endgraph;
  end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH3;
run;


④ 「LAYOUT LATTICE」 と 「LAYOUT OVERLAY」 を組み合わせる

* グラフテンプレート作成 ;
proc template ;
  define statgraph MYGRAPH4;
      begingraph ;
          layout lattice;
              layout overlay;
                  scatterplot x=WEIGHT y=HEIGHT;
                  regressionplot x=WEIGHT y=HEIGHT;
              endlayout;
              boxplot x=AGE y=HEIGHT;
          endlayout;
      endgraph;
  end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH4;
run;

上は「LAYOUT OVERLAY」で散布図と回帰直線を重ねたグラフで、
下は箱ひげ図をプロットして並べています。


LAYOUT GRIDDED

LAYOUT GRIDDEDも、PLOTを左右上下に並べる事ができます。

* グラフテンプレート作成 ;
proc template ;
  define statgraph MYGRAPH5;
      begingraph ;
          layout gridded;
              boxplot x=AGE y=HEIGHT;
              boxplot x=AGE y=WEIGHT;
          endlayout;
      endgraph;
  end;
run;

* グラフ作成実行 ;
proc sgrender data=SASHELP.CLASS template=MYGRAPH5;
run;

「LAYOUT LATTICE」と 「LAYOUT GRIDDED」の大きな違いとして、 
「LAYOUT LATTICE」では、オプションやステートメントを指定することで、PLOT間の軸を共通化させたり色々出来るところ。

詳細はまた別の機会にて。。


GTL入門記事一覧