2015年10月19日月曜日

最初の1バイト目だけ大文字に変換する


たとえば「abc def」→「Abc def」のような変換です。


前提条件
・ 最初の1バイト目はアルファベットである事。
・ 対象変数は半角の英数記号のみである事。


サンプルデータ

data DT1;
   length VAL $20.;
   VAL="proc print"; output;
   VAL="data step"; output;
run;

 VAL  
  proc print  
  data step



先頭の1バイト目だけ大文字にする

data DT2;
   length VAL2 VAL3 $20.;
   set DT1;

   * ① SUBSTR関数を使う ;
   VAL2 = upcase(first(VAL)) || substr(VAL,2);

   * ② 正規表現を使う ;
   VAL3 = prxchange('s/(^[a-z])/\U$1/', 1, VAL);
run;

 VAL2  
 VAL3  
 VAL  
 Proc print Proc print  proc print 
 Data step  Data step  data step

① SUBSTR関数を使う方法
FIRST関数は1バイト目を抜き出す関数
つまり1バイト目を抜き出して大文字にしたものと、2バイト目以降の文字を結合しています。

② 正規表現を使う方法
PRXCHANGE関数で正規表現による置換をしてます。
「prxchange('s/(^[a-z])/\U$1/', 1, VAL)」

(^[a-z])」は先頭の文字がa~zのいずれかである場合、、という意味。
\U$1」は上記を大文字に変換しています。


2015年10月15日木曜日

Graph Template Language(GTL)入門:MVARステートメント【マクロ変数を引数にする】

 


まずは構文をご覧ください。



構文

 PROC TEMPLATE ;
      DEFINE STATGRAPH テンプレート名;
            MVAR    マクロ変数1  マクロ変数2 ・・・ ;
            NMVAR  マクロ変数1  マクロ変数2 ・・・ ;

            ~ グラフテンプレート作成処理 ~
      END;
 RUN;

  • MVAR に指定したマクロ変数は、PROC TEMPLATE内で文字の設定値として参照可能になる。
  • NMVAR に指定したマクロ変数は、PROC TEMPLATE内で数値の設定値として参照可能になる。


例を見ていきましょう。


ステップ1・・・ グラフテンプレートの作成

proc template;
    define statgraph MYGRAPH;
    mvar  m_TITLE m_XVAR m_YVAR;
    nmvar  m_XREF;

    begingraph;
         entrytitle m_TITLE;
         layout overlay;
             scatterplot x=m_XVAR y=m_YVAR;
             referenceline x=m_XREF / curvelabel="特に意味はない参照線";
         endlayout;
    endgraph;
    end;
run;

  • mvar m_TITLE m_XVAR m_YVAR」で、マクロ変数「m_TITLE」~「m_YVAR」を文字の設定値として参照可能にする。
  • nmvar m_XREF」で、マクロ変数「m_XREF」を数値の設定値として参照可能にする。
  • entrytitle m_TITLE」で、グラフのタイトルにマクロ変数「m_TITLE」を設定。
  • scatterplot x=m_XVAR y=m_YVAR」で、散布図のX軸にマクロ変数「m_XVAR」、Y軸にマクロ変数「m_YVAR」を設定。
  • referenceline y=m_XREF」で、X軸の参照線にマクロ変数「m_XREF」を設定。



ステップ2・・・ マクロ変数に値を設定して、グラフ作成実行

%let m_TITLE = 散布図;
%let m_XVAR = AGE;
%let m_YVAR = HEIGHT;
%let m_XREF = 12;

proc sgrender data=SASHELP.CLASS template=MYGRAPH;
run;



  • ステップ1で使用しているマクロ変数「m_TITLE」~「m_XREF」に値を設定。
  • PROC SGRENDERでグラフ作成を実行しています。



覚えておきたいポイント


ポイント1
MVAR/NMVARの細かいルールでミスってうまく動かないことが多いので、リファレンスを参照しつつ、実行後にログや出力結果を確認するようにしましょう。

例えば、以下の青字部分をご覧ください。

proc template ;
    define statgraph MYGRAPH;
        nmvar m_XLIST;
        begingraph;
           layout overlay / xaxisopts=(linearopts=
              (viewmin=0 viewmax=200 tickvaluelist=m_XLIST));
                scatterplot x=WEIGHT y=HEIGHT;
           endlayout;
        endgraph;
    end;
run;

%let m_XLIST = 0 100 200;
proc sgrender data=SASHELP.CLASS template=MYGRAPH;
run;




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

tickvaluelist=(0 100 200)


NMVARでマクロ変数を設定する場合、カッコは不要。

tickvaluelist=m_XLIST


マクロ変数に値を設定する際も、カッコは不要です。

%let m_XLIST = 0 100 200;



ポイント2
データステップ100万回「マクロ変数に数値をいれて戻すと誤差がでちゃう場合がある問題について考える話
で解説されてるように、マクロ変数に小数をいれると切り捨てられる可能性があるのでご注意ください。


ポイント3
本題と逸れますがマクロ変数は「スコープ」というものを理解していないと、落とし穴にはまってしまうことがあります。スコープについては以下記事を参照下さい。

関数
マクロ変数を引数にする
軸の設定

2015年10月13日火曜日

比較演算子のアルファベット表記と、ちょっとした小技





IF / WHEREステートメントで用いる比較演算子は、アルファベット2文字で書くことができます。

 比較演算子  別の書き方  意味 
 = EQ equal to
 ^= NE not equal to
 > GT greater than
 < LT less than
 >= GE greater than or equal to
 <= LE less than or equal to


たとえば 「if A=1」 は 「if A eq 1」 とも書けます。

海外のSASプログラムを見てると、このアルファベット2文字を使ってる事が結構あります。

各自が好きな書き方でプログラミングを楽しめるのが一番だと思いますが。。
まわりのSASプログラマに聞いてみたら、この書き方は結構受けが悪かったです。




ちょっとした小技

受け悪いって方にも、使えるかもしれないテクニックを紹介。
以下をご覧ください。

%macro SAMPLE( WH );
     data DT1;
          set SASHELP.CLASS;
          where &WH;
     run;
%mend;

%SAMPLE( AGE = 13 );

ログ
 ERROR: キーワードパラメータAGEは、マクロに定義されていません。


詳細は割愛しますが、
%SAMPLE( AGE = 13 )」 で 「AGE = 13」 という引数を指定したわけですが、引数にイコール「=」があると、キーワードパラメータというものとして解釈され、今回の意図とは異なる動きをしてエラーとなってしまいました。


通常の解決方法として、%STR関数等で 「=」 の効力を無効化してやります。

%SAMPLE( %str(AGE = 13) );



そして、もうひとつの解決方法。

%SAMPLE( AGE eq 13 );




アルファベット表記に変えてしまえば、「=」 を使わなくて済むというわけです。



2015年10月9日金曜日

マクロ実行文をログに展開するMPRINTとMPRINTNEST


他の方が書いたSASプログラムを引き継いで運用するって事ありますよね。
そんな時に今回紹介するオプションが結構役に立ちます。


まず以下のプログラムがあったとします。
* 適当な例 ;
%macro TEST;
     X=1;
%mend;

%macro TEST2;
     data DT1;
         %TEST
     run;
%mend;

マクロ[TEST2]の中で別のマクロ[TEST]を呼び出しているプログラムです。


ここで MPRINT オプションを設定してマクロを実行すると、、
options mprint;
%TEST2;


ログ
MPRINT(TEST2):   data DT1;
MPRINT(TEST):   X=1;
MPRINT(TEST2):   run;

上のログのように、展開されたマクロがログに出力されます。


さらにMPRINTNEST オプションも合わせて設定すると、、
options mprint mprintnest;
%TEST2;


ログ
MPRINT(TEST2):   data DT1;
MPRINT(TEST2.TEST):   X=1;
MPRINT(TEST2):   run;

MPRINT(マクロ名1.マクロ名2) という風にネストされているマクロ名がすべて出力されます。

設定を戻すには 「options nomprint nomprintnest ;」と書けばok


マクロって便利ですが、ネストしまくると読みづらいプログラムになりがちです。
そういった時、上記オプションを設定することで、マクロの動きが分かり易くなる場合があります。


2015年10月4日日曜日

「ODS POWERPOINT」によるパワーポイントへの出力(SAS9.4からの機能)


SAS9.4から追加された 「ODS POWERPOINT」 について、ざっくりまとめました。



構文

ODS POWERPOINT  LAYOUT=スライドの種類   FILE="出力ファイルのフルパス OPTIONS( オプション );

         ~ プロシジャ等による出力処理を記述  

ODS POWERPOINT  CLOSE;

スライドの種類
・TitleSlide            : タイトルのみ
・TitleAndContent : タイトルとコンテンツ
・TwoContent        : コンテンツを横に2つ並べる



例 

同じSAS9.4でも、メンテナンスリリースのタイミングで追加されたオプションもあるので、以下の例が正しく動作するかは各環境でご確認下さい。

*** スライド1枚目 ;
ods powerpoint  layout = TitleSlide
   file = "各自の出力するファイルのフルパスを指定"
   options( backgroundimage="linear-gradient(90deg, white, skyblue)" );

   proc odstext ;
      p "適当にスライドを作ってみる"  / style=presentationtitle;
      p "by SAS忘備録" / style=presentationtitle2;
   run;

*** スライド2枚目 ;
ods powerpoint layout = TitleAndContent;

   title "集計";
   proc means data=SASHELP.CLASS n mean std min max;
      var HEIGHT WEIGHT;
      class SEX;
   run;

*** スライド3枚目 ;
ods powerpoint layout = TitleAndContent;

   title "散布図";
   proc sgplot data=SASHELP.CLASS;
      scatter x=HEIGHT y=WEIGHT / group=SEX;
   run;

ods powerpoint close;

出力結果


スライド中のテキストは、SAS9.4から追加されたODSTEXTプロシジャというもので出力します。
なかなか面白いプロシジャですが、詳細は割愛。。


今回はSASのマニュアルのほか、以下SASユーザー総会2015で発表された資料を参考にさせていただきました。

「ODS POWERPOINTの活用:SASからMicrosoft Powerpointへのエクスポート」
https://www.sas.com/content/dam/SAS/ja_jp/doc/event/sas-user-groups/usergroups2015-d-04.pdf

最新の機能(ODSTEXT・ODSLIST・DOCUMENTプロシジャ)なども合わせて紹介されていて、私の大好きな発表です。


2015年10月1日木曜日

暗黙のOUTPUTステートメント



今回の内容は、PDV(プログラムデータベクトル)を理解していないと、正確な動きを理解しづらいかも。

あと、データステップ中にMODIFYステートメントを使用していない前提での説明となります無限ループになったり挙動が変わることがあるので・・)



サンプルデータ

data DT1;
   length A 8.;
   A=1; output;
   A=2; output;
run;

  A  
  1
  2



暗黙のOUTPUT


以下は単純なデータステップですが、、

data OUT1;
   set DT1;
run;

内部では、SETに指定した「DT1」から1オブザベーション毎にPDV(読み込んだデータを入れておく一時的な箱)で処理してから、出力データセット「OUT1」に出力していて、
この処理の流れが「DT1」から1オブザベーションずつ、全オブザベーションに対して反復されます。


そして実は、データステップの各反復の最後にOUTPUTステートメントが自動で実行されています。
(以下はあくまでもイメージ)

data OUT1;
   set DT1;
   output;
run;


OUTPUTステートメントとは、
読み込んだオブザベーションに対する処理結果を、データセットに出力するステートメントです。

つまりOUTPUTが自動で実行されるおかげで、データセットへの出力ができているわけです。
(これを「暗黙のOUTPUT」と呼びます)



例外


以下のようにプログラマ側が明示的にOUTPUTステートメントを記述した場合、、

data OUT2;
   set DT1;
   if A=2 then output;
run;

  A  
  2

明示的に記述したOUTPUTが優先され、暗黙のOUTPUTは実行されなくなります。



注意


以下の実行結果は想定通りでしょうか?

data OUT3;
   length A B C 8.;
   A=1;
   B=1;
   output;
   C=1;
run;

 A  
 B  
 C  
  1  1  .

① まず「output;」によって、明示的にOUTPUTを行うタイミングを変えています。
② 次に「C=1;」とありますが、①で既にデータセットへの出力が済んでるため、この処理結果はデータセットに反映されません。よってCは欠損値になります(変数自体は作られます。データステップで作成した変数は記述位置に関係なく変数の枠が最初に作られるので)


ちなみに、明示的なOUTPUTを複数記述することもできます。

data OUT4;
   length A B C 8.;
   A=1;
   B=1;
   output;
   C=1;
   output;
run;

 A  
 B  
 C  
  1  1  .
  1  1  1

OUTPUTする度に、データセットにオブベーションが追加され、
2個目のOUTPUTで「C=1;」が反映されたオブザベーションが追加されています。


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関数で実行日時をフッターに表示してます。



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