2017年12月13日水曜日

SASの処理は1obsごとに行われていると言う話

これは私のプログラム力が低いと言う話です.
何を今更こいつ......となるかもですが,そこはそっとしてあげてください

data DAT1 ;
    a = 1 ; n = 10 ; output ;
    a = 3 ; n = 20 ; output ;
    a = 4 ; n = 30 ; output ;
    a = 6 ; n = 50 ; output ;
run ;

これまで上のデータセットから,a=1の時のnの値をマクロ変数に入れる時は
「if a = 1 then call symputx("_all1" , N)」と書いていたわけです.
同様にa = 2 の時のNを格納したマクロ変数を作る時は,
「if a = 2 then call symputx("_all2" , N)」と書いていました.

これって1つとか2つとかならいいんですが,3つ4つとマクロ変数を作らないといけない時は
下の様にif文をいっぱい書いていたわけです.ほんと無駄ですね.

data _null_ ;
    set DAT1 ;

    *---------- Aの値毎にマクロ変数作る時にif文で分岐させてた ;
    if A = 1 then call symputx("_all1" , N)
    if A = 3 then call symputx("_all3" , N)
    if A = 4 then call symputx("_all4" , N)
    if A = 6 then call symputx("_all6" , N)

    *---------- 同じことが1行で書けちゃう ;
    call symputx( cats("_all" , A) , N) ;

run ;

別に1obsごとに実行するのはマクロ変数作る時だけではないです.…今更ですね

data MOLEC ;

    A = 1 ; COUNT = 5 ;  output ;
    A = 3 ; COUNT = 10 ; output ;
    A = 4 ; COUNT = 20 ; output ;
    A = 6 ; COUNT = 11 ; output ;

run ;

data HOGE ;
    set MOLEC ;
   
    *---------- 今まではifで分岐させてマクロ変数を指定して割り算していた ;
    if A = 1 then OUT = round(COUNT / &_all1 , 1e-08) ;
    if A = 3 then OUT = round(COUNT / &_all3 , 1e-08) ;
    if A = 4 then OUT = round(COUNT / &_all4 , 1e-08) ;
    if A = 6 then OUT = round(COUNT / &_all6 , 1e-08) ;

    *---------- 同じことが1行で書けちゃう ;
    OUT2 = cats(COUNT / symgetn( cats("_all", A) ) , 1e-08) ;

run ;

いやー自分のスキルのなさが恥ずかしい

あ,いまさらツイッタ始めました
<https://twitter.com/dap123586>


2017年11月8日水曜日

SASのnotepadの話

SASにNOTEPADが実装されています(9.3で確認)
拡張エディタと同様にプログラムを書いて実行することが出来ます.

拡張エディタとの違いは,NOTEPADに書いた内容はSASを落としても保存される点です.
拡張エディタに書いた内容は外部ファイルに保存しない限りSASを落とすと消えますが,
NOTEPADに書いた内容はSASを新しく立ち上げなおしても保持されたままになっています.

このプログラムを一度きれいな環境で実行したい,とかの時に便利だと思っています.
限られた状況ですが...

NOTEPADを起動するには,
dm "notepad" ;
と拡張エディタで実行します.

NOTEPADに書いたプログラムを実行するには
dm notepad "notesubmit" ;
と拡張エディタで実行するか,ツールバーからボタンで実行を選ぶかです.
実行したログは普通にログ画面にいつも通りに表示されます.

NOTEPADの中身は
dm notepad "clear" ;
できれいになります.

dm notepad "close" ;
を実行するとNOTEPADは閉じます.
これだと閉じただけですので,NOTEPADの中身は保存されています.

NOTEPADのいまいちなところはキーボードマクロが使えないところと,ハイライトが付かないところですかね…

2017年10月15日日曜日

9.4のメンテナンスリリース5がでてるやんけぇと言う話

出てますね,9.4M5.
日本語での案内ってでますかねこれ.
イマイチ見当たらないんですが.
sas studioも9.4M4なので実際に触れないのですが,いくつか新機能が出ているようです.
そのうちの二つを紹介しようと思います.

proc dstods2 がそのうちの1つです.
なんでもデータステップをDS2言語に変換して出力するプロシジャのようです.
inにsasプログラムをよみこんで,outから「.ds2」形式のファイルを出力するようです.
データステップのhashも一部対応してるよ!(Partial support for the hash object. )
とのことなので実際にいろいろ変換してみたいのですが,いかんせん9.4M5が触れないですね
幾つか未対応の機能もあるようなので,そこは気を付けたいところです.

該当のdocument
<http://documentation.sas.com/?cdcId=pgmsascdc&cdcVersion=9.4_3.2&docsetId=proc&docsetTarget=p0zok9sr2a2t46n1r8zfuw5145t5.htm&locale=ja>

取りあえず以下はsasのdocumentから引っ張ってきた例です.

data _null_;
   length x y z w 8;
   set x;
   by x--z w;
   put x=;
run;

このデータステップをdsex1.sasに保存して

proc dstods2 in="dsEx1.sas" out="ds2Ex1.ds2"; run;

上のプロシジャに掛けると,
下の様なコードがds2ex1.ds2として出力されるようです.

data _NULL_;
  dcl double X;
  dcl double Y;
  dcl double Z;
  dcl double W;
  method run();
  set X;
  by  /* X--Z */ W;
  put X=;
  ;
  _return: ;
  end;
enddata;

もう一つはgzフォルダにfilenameステートメントでアクセスできるようになったようです.
filenameステートメントのzipオプション下でgzipオプションをつければアクセス可能になるとのこと.
ただgzipオプションとmemberオプションの両方を書くと,memberオプションは無効になるようですね.

と言うか9.4からZIPにはアクセス出来るようになってたんですね.
そこすら知らなかったです.

filename foo ZIP 'U:\directory1\testzip.zip' member="test1.txt" 
これで指定したzipの中のtest1.txtにアクセス出来るらしいです.

該当のdocument
<http://documentation.sas.com/?cdcId=pgmsascdc&cdcVersion=9.4_3.2&docsetId=lestmtsglobal&docsetTarget=n1dn0f61yfyzton1l2ngsa1clllr.htm&locale=ja#p0c653wf2di4jln10vjxwuub1ptz>


後はviyaを見据えた変更点がありそうなくらいですかねぇ
にわか知識なのであまり詳しいことはわかりませんが.
日本語の記事とかあったら知りたいです.

2017年10月10日火曜日

sas studioにログインできなかった話

まさかの月に複数回更新

久しぶりにSAS studioにログインしようとすると入れませんでした.
どうもライセンスを更新しないといけない様子です
sasのsupportページ<https://support.sas.com/ondemand/caq_new.html>の
「general questions」のところに記載がありました.

Q.
I am unable to sign on to the Control Center or other SAS OnDemand for Academics software applications.

A.
You may be using a mixed or upper-case user ID. Only lowercase values are acceptable for your user ID. Additionally, you may be using the wrong password or your account may be disabled. You must renew your license agreement each year. Your account will be disabled if you fail to renew.
  •  If you have forgotten your password or wish to reset it, see What should I do if I forget  my password?
  •  If you have reset your password and are still unable to sign on, you can sign on to the Registration application and update your license agreement. After that,    you can try to sign on again.
  •  If you have tried both of these items and are still unable to sign on, then you can send e-mail to SASAnalyticsU@sas.com to receive technical support.

二つ目の○のところに,「update your license agreement」と書いてあります.
Ansの部分の概要に,「You must renew your license agreement each year.」とあるので,一年に一回はライセンスを更新しないといけないようです.

/*----- 20190110追記 ------*/
ココ勘違いしている気がします.年一回アカウントの更新が必要なのではなく,年に一回はログインしないとアカウントの更新が必要になるんじゃないでしょうか.
どっかでログインしていればアカウントの更新をしなくてもいいはずです.
/*----- 20190110追記ここまで ------*/

ここからは更新の仕方についてです.
アカウントを作るページ<https://odamid.oda.sas.com/SASODARegistration/>に
自分が作ったアカウントのFirst name,Last name,email addressを入力してCountryを選んでsubmitします.
(更新なのにCreate an accountのページなのが違和感ありますね.そんなもんなんでしょうか)

submitすると,「You are already registered with SAS OnDemand for Academics. 」と言われるので,
下のテキストボックスにアカウントのパスワードを入れて「continue」をクリックです.
この時にlicenseにagreeする旨のチェックボックスにチェックを入れてください

次のページで「Your account is ready to use. 」と出てくるので,これでOKです.
このページで自分のUSERIDを教えてくれますので,ログイン時はそのIDと設定したパスワードを使ってください.

これで一年間はまた使えるはずです.
一年後にまたライセンスの更新を忘れずにしましょう

2017年10月2日月曜日

sgplotを実行した時に,自動でグラフのイメージが出力される話

改めて見るとよくわからないタイトルですね.適当よくない

sgplotでグラフを書くと,グラフのイメージが勝手にpng形式で出てきて困ってました.
ods rtfでrtf形式を指定しているので,改めてpngは要らないのです.
そういう時は「ods listing close ;」でpngの出力止めれますよ,と言う簡単な話です.

それか出力先を自分のsasのworkにしてしまえば,
sasを落とせば勝手に消えるし出力の確認もできます.
workをこんな使い方していいのかは知りませんが.

*----- pngの出力止める(outputへの出力を止める) ;
ods listing close ;

*----- rtf出力start ;
ods rtf file = "hogehoge\test.rtf" ;

proc sgplot data = sashelp.class ;
     vbox HEIGHT / category = SEX ;
run ;

ods rtf close ;
ods listing ;


/*---------- 出力をworkにする ----------*/
%let _wk = %sysfunc(getoption(work));
%put &=_wk ;

*----- outputの出力先を指定 ;
ods listing gpath = "&_wk."

2017年9月27日水曜日

wilcoxon順位和検定の話_npar1wayプロシジャ

対応の無い2群間の比較をする際,wilcoxon順位和検定を実行するときはあると思います.
この検定をSASで実行するには,npar1wayプロシジャのwilcoxonオプションを用います.
この検定は「2群間の比較」であることに注意してください.

univariateプロシジャでも2群の比較をすることはできますが,
univariateプロシジャではwilcoxonの「符号」順位和検定を行うことが出来ます.
この検定は今回のwilcoxon順位和検定と違い,対応のある2群間比較になるので割愛します.

/*---------- testdata ----------*/
data hoge ;
    cat = "A"; var1 = 1 ; output ;
    cat = "A"; var1 = 1 ; output ;
    cat = "A"; var1 = 1 ; output ;
    cat = "A"; var1 = 2 ; output ;
    cat = "A"; var1 = 2 ; output ;
    cat = "A"; var1 = 3 ; output ;
    cat = "A"; var1 = 3 ; output ;
    cat = "A"; var1 = 3 ; output ;
    cat = "A"; var1 = 3 ; output ;
    cat = "A"; var1 = 3 ; output ;
    cat = "A"; var1 = 4 ; output ;
    cat = "A"; var1 = 4 ; output ;
    cat = "A"; var1 = 4 ; output ;
    cat = "A"; var1 = 5 ; output ;
    cat = "A"; var1 = 5 ; output ;

    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 1 ; output ;
    cat = "B"; var1 = 2 ; output ;
    cat = "B"; var1 = 2 ; output ;
    cat = "B"; var1 = 3 ; output ;
    cat = "B"; var1 = 4 ; output ;
    cat = "B"; var1 = 5 ; output ;
    cat = "B"; var1 = 6 ; output ;
    cat = "B"; var1 = 6 ; output ;
run ;

proc npar1way data=HOGE wilcoxon ;
      class CAT ;
      var VAR1 ;
      output out = NPAR ;
run;

正規分布で近似した時の片側P-値は「PR_WIL」
同じ時の両側P-値は「P2_WIL」の変数に格納されています.

結果のデータセットの全体像








おまけですが,npar1wayプロシジャを動かした時の結果の名前の一覧を以下に貼ります.
ods trace on した時に出てくるやつです.
上のプログラムでoutput outで指定すると全ての結果がデータセット化されますが,
結果の名前を指定してods outputすると,データセット化する結果を選ぶことが出来ます.














2017年8月25日金曜日

平均の信頼区間を求める話_proc means

なんかの測定値の平均の95%信頼区間を求めたいときは往々にしてあると思います.

あちこちに載っていますが,そんな時はproc meansで出せますよ,という話です.
proc univariateでも出せますが,結果をデータセット化するのはproc meansのほうが簡単だと思います.

meansでlclm(信頼区間の下限),uclm(信頼区間の上限)を指定するだけです.簡単ですね.

/*----- test data -----*/
data aa ;
    a = 1 ; b = 1 ; output ;
    a = 2 ; b = 1 ; output ;
    a = 3 ; b = 1 ; output ;
    a = 4 ; b = 1 ; output ;
    a = 5 ; b = 1 ; output ;
    a = 6 ; b = 1 ; output ;
    a = 9 ; b = 2 ; output ;
    a = 8 ; b = 2 ; output ;
    a = 7 ; b = 2 ; output ;
    a = 5 ; b = 2 ; output ;
    a = 6 ; b = 2 ; output ;
run ;

proc means data = AA noprint nway ;
    var A ;
    class B ;
    output out = HOGE n = lclm = uclm = / autoname ;
run ;

2017年7月12日水曜日

マクロ変数を作成するときに引っかかった話

マクロ変数の値を呼び出すときに、思ってたのと違う値が出てきた時があったのでそれを紹介する話です。

マクロ変数をローカルマクロとして定義した後、同じマクロ変数名でグローバルマクロ変数としてもう一度定義して、そのマクロ変数を呼び出そうとしました。

私のイメージではグローバルマクロ変数として定義したほうの値が取れてくると思ったのですが、先に定義したはずのローカルマクロ変数の値が取れてくる時がありました。
とりあえず以下にプログラムを書いときます。
しかし不思議ですねえ

data DT_TEST ;
    _AA=1 ; output ;
    _AA=2 ; output ;
    _AA=3 ; output ;
run ;
%macro MCR_TEST ;

    *----------  ローカルマクロを指定;
    %let _aa2=123 ;
    data _NULL ;
        set DT_TEST ;
       
        *----------  グローバルマクロを指定;
        call symputx("_aa2",_N_,"g") ;
    run ;
    *----------  マクロ変数を呼び出し;
    %put &_aa2 ;

%mend ;

*----------  1回目:ローカルマクロとしての値(123)が返る;
%MCR_TEST ;


*----------  2回目以降:グローバルマクロとしての値(3)を返す;
%MCR_TEST ;

2017年6月19日月曜日

whereステートメントでデータセットを抽出するときの話

データセットをwhereステートメントを使って抽出するとき、
コピペミスをして一つのデータステップにwhereステートメントを2回書いてしまいました。
実行したらどうなるのだろうと思って実行すると、

data hoge;
    a = 1; output;
    a = 10; output;
    a = 100; output;
run;

/*これ↓*/

data hogehoge;
    set hoge;
    where a = 1;
    where a = 10;
run;












と、1つ目のwhereが二つ目の式に書き換えられるんですね
結果二つ目のwhereステートメントのみで絞ったのと同じ結果になる、と。

じゃあと思ってsetのオプションにwhere書いたらどうなるのだろうと思い

data hogehoge;
    set hoge(where = (a = 1));
    where a = 10;
run;
とすると、




を実行すると、これはwarningになるのですね

今まで書いたことなかったので知りませんでした。
知ってて当然、なのかもしれませんが。




2017年5月25日木曜日

信頼区間を求めるお話_FREQプロシジャ

変数の値が0,1の二値を取る時に信頼区間を求めるお話です

信頼区間を求めたい変数に、0と1の両方があれば良いのですが
値として0しかない、1しかない時は往々にしてあると思います。
そんな時はweightステートメントにzeroesオプションを付けましょうと言うお話です。

tabelsステートメントの(level='1')は変数の値が1のものをpositiveとして計算してください、の意味です。
これも良く忘れて、二値データのどっちがpositiveだっけ?となる…気がします

/* ---------- ここからプログラム --------- */
*---------- test data/水準0がなく、1しかないデータ;
data hoge;
    a = 1; output;
    a = 1; output;
    a = 1; output;
run;

*---------- 後でweight考慮するために集計;
proc freq data = HOGE  noprint;
    tables a / out = HOGE_FREQ ;
run;

*---------- dummy data;
data DUM;
    a = 0; COUNT = 0; output;
    a = 1; COUNT = 0; output;
run;

*---------- データに無い水準は0件としてデータに持たせる;
data HOGE2;
    merge DUM HOGE_FREQ ;
    by A;
    drop PERCENT;
run;

*---------- 信頼区間/正確な信頼区間はXL_BIN-XU_BIN;
proc freq data = HOGE2  noprint;
    tables a / binomial(level = '1');
    exact binomial;
    weight COUNT / zeroes;
    output out = TEST_OUT;
run;

2017年5月11日木曜日

実行日時を取得する話

月1の更新は維持できると思っていた、そんな時代も今は昔

実行した日時を取得するプログラムを今まで思考停止して使っていましたが
よく見ると複雑な書き方をしていたので書き直してみました。
実行結果は変わらず、対して実行時間も変わらないので完全に自己満足の世界ですね
年月日_日時の形式で実行日時が取得できます。

/*以下が以前私が使っていた日時取得プログラム*/
data _null_;
    length _DAY DAY TIME DATETIME $20;
   
    now = datetime();                                                        
    _DAY = put(datepart(now) , yymmdd10.);                                   
    DAY  = compress(_DAY,"-");                                               
   
    TIME = compress(put( timepart(now) , hhmm5.) , ':');
   
    DATETIME = trim( left(DAY) )||'_'||trim( left(TIME) );
    call symput('today', trim( left(DATETIME) ) );
run;
/*--ここまで以前のもの-----*/

/*--ここから新しく作ったもの--------*/
data _null_;
    length DAY TIME $10;
    DAY  = put(today() , yymmddn8.);
    TIME = compress(put(time() ,tod5.) , ,"dk");
    call symputx("_today" , catx("_" , DAY , TIME) );
run;

2017年3月21日火曜日

複数のグラフを1枚にまとめる話_今回は4枚のグラフを一つに

何枚かのグラフを一枚の紙に出力したいときのお話です。
グラフをまとめるのはgreplayプロシジャを使います。
GTLさんには座っててもらいましょう。

以下のプログラムは
・1ページに4枚のグラフを並べて表示
・IDごとに改ページ
・一つのIDの中でもグラフ4枚ごとに改ページ
したRTFファイルを出力するものです。

一番下のods rtfで指定した場所にhoge.rtfが出てきます。

以下の3枚の画像が出力イメージです。






--ここからプログラム-----

/* ---------- testdata --------- */
data test;
    id = 1; cd = 1 ; time = 1; value = 1; output;
    id = 1; cd = 1 ; time = 2; value = 1; output;
    id = 1; cd = 1 ; time = 3; value = 1; output;
    id = 1; cd = 1 ; time = 4; value = 1; output;
    id = 1; cd = 1 ; time = 5; value = 1; output;
    id = 1; cd = 2 ; time = 4; value = 2; output;
    id = 1; cd = 2 ; time = 5; value = 2; output;
    id = 1; cd = 2 ; time = 6; value = 2; output;
    id = 1; cd = 2 ; time = 7; value = 2; output;
    id = 1; cd = 2 ; time = 8; value = 2; output;
    id = 1; cd = 3 ; time = 1; value = 3; output;
    id = 1; cd = 3 ; time = 2; value = 3; output;
    id = 1; cd = 3 ; time = 3; value = 3; output;
    id = 1; cd = 3 ; time = 4; value = 3; output;
    id = 1; cd = 4 ; time = 4; value = 4; output;
    id = 1; cd = 4 ; time = 5; value = 4; output;
    id = 1; cd = 4 ; time = 6; value = 4; output;
    id = 1; cd = 5 ; time = 2; value = 5; output;
    id = 1; cd = 5 ; time = 6; value = 5; output;
    id = 1; cd = 5 ; time = 7; value = 5; output;
    id = 1; cd = 5 ; time = 9; value = 5; output;
    id = 2; cd = 1 ; time = 1; value = 1; output;
    id = 2; cd = 1 ; time = 2; value = 1; output;
    id = 2; cd = 1 ; time = 3; value = 1; output;
    id = 2; cd = 1 ; time = 4; value = 1; output;
    id = 2; cd = 2 ; time = 3; value = 2; output;
    id = 2; cd = 2 ; time = 4; value = 2; output;
    id = 2; cd = 2 ; time = 5; value = 2; output;
    id = 2; cd = 3 ; time = 1; value = 3; output;
    id = 2; cd = 3 ; time = 2; value = 3; output;
    id = 2; cd = 3 ; time = 3; value = 3; output;
    id = 2; cd = 3 ; time = 4; value = 3; output;
run;

/* ---------- 出力 --------- */
  goptions gunit=pct;a
  goptions
      reset   = all
      gsfmode = replace
      xmax    = 6 in
      ymax    = 9 in
      vsize   = 5 in
      hsize   = 9 in
  ;
*-========================================;
*-グラフ出力位置指定(4枚)*;
  proc greplay gout=work.gseg tc=work.tmplt nofs;
    tdef PK1
   
    1 / llx=0 lly=50                                                            /*left upper panel*/
        ulx=0 uly=100
        lrx=50 lry=50
        urx=50 ury=100
   
    2 / llx=50 lly=50                                                           /*right upper panel*/
        ulx=50 uly=100
        lrx=100 lry=50
        urx=100 ury=100
   
    3 / llx=0 lly=0                                                             /*left lower panel*/
        ulx=0 uly=50
        lrx=50 lry=0
        urx=50 ury=50
   
    4 / llx=50 lly=0                                                            /*right lower panel*/
        ulx=50 uly=50
        lrx=100 lry=0
        urx=100 ury=50
   ;
  run;
  quit;

goptions gunit=pct ;
%macro grepout(_indt = , _wh = );
*---------- annotate macroを有効にする;
%annomac;

*---------- 各グラフの出力を一旦抑制/まとめたグラフ以外は出力不要;
goptions nodisplay;

*---------- 種類をマクロ変数に格納;
data FDAT;
    set &_indt.(where = (&_wh.)) end = _EOF;
    if _eof = 1 then do;
        CD4 = ceil(CD/4);
        call symputx("_n" , CD);
        call symputx("_n4" , CD4);
    end;
    drop CD4;
run;

*---------- CDの種類だけGPLOTを実行;
%do i = 1 %to &_n ;

    *---------- nameを取得/グラフにnameを表示する;
    data _NULL_;
        set TEST(where = (CD = &i. and &_wh.));
        call symputx("_name" , CD);
        call symputx("_id" , ID);
    run;

    ods escapechar = '^' ;

    data anno1;
        set TEST(where = (CD = &i.));
        length TEXT $80;
        %dclanno;
        %system(3,3,3);
 
        *---------- 軸ラベル;
        %label(20, 95  , "CDが&_name.のグラフ" , black, 0, 0, 4 , 'Arial'  , 5);
        %label(80, 95  , "IDが&_id.のグラフ" , black, 0, 0, 4   , 'Arial'  , 5);
    run;

    proc gplot data = FDAT(where = (CD = &i.)) anno=anno1;
 
        plot  VALUE  * TIME   / nolegend vaxis = axis1 haxis = axis2 skipmiss ;      
        symbol1 mode = include v = triangle h = 2 c = black  i = join l = 21 w = 1.5;

        axis1                                                                   /*y軸目盛*/
          label=none
          offset=(2,2)  minor=none major=(w=1.5 h=0.8)
          length=60 width=1 order=(0 to 6 by 1)
          value=(font='Times New Roman' h=4 )
          origin=(10.3, 30);

        axis2                                                                   /*x軸目盛*/
          label=none
          offset=(2, 2)  minor= none  major=(w=1.5 h=0.8)
          length=80 width=1 order=( 1 to 9 by 1 )
          value=(font='Times New Roman' h=4 )
          origin=(10.3, 30);
    run;
    quit;
%end;

*---------- グラフの出力を再開_4グラフ1ページのものだけを出力;

goptions hsize = 9 in display;

*-出力;
    %macro greplay/*(path=, out=)*/;
      %put Number of Parameter is &_n;
      %put Number of Page is &_n4.;
      %do i = 1 %to &_n4. %by 1;
       
        %if %eval(&i) = 1 %then %let j = 1;
                          %else %let j = %eval(&j + 4);
        %put i is &i.;
        %put j is &j.;
        proc greplay igout=work.gseg gout=work.gseg tc=work.tmplt nofs;
          template PK1;
          %if &_n4. = 1  %then %do;
            treplay 1:gplot
                    2:gplot1
                    3:gplot2
                    4:gplot3
            ;
          %end;
          %if &_n4. >= 2 and &i = 1 %then %do;
            treplay 1:gplot
                    2:gplot1
                    3:gplot2
                    4:gplot3
            ;
          %end;

          %if &_n4 >= 2 and &i >= 2  %then %do;
            treplay 1:gplot%eval(&j - 1)
                    2:gplot%eval(&j)
                    3:gplot%eval(&j+1)
                    4:gplot%eval(&j+2)
            ;
          %end;
        quit;
      %end;
    %mend greplay;
    %greplay

    *---------- 出力したグラフをリセット;
    proc catalog  catalog = work.Gseg kill  ;
        run;
   
    quit ;
%mend grepout;

ods listing close;
ods rtf file = "hogehoge\hoge.rtf";

%grepout(_indt = TEST , _wh = %nrstr(ID = 1) );
%grepout(_indt = TEST , _wh = %nrstr(ID = 2) );

ods rtf close;
ods listing;

2017年2月14日火曜日

annotateマクロの%systemの話

gplotなりsgplotなりグラフを作る時に、annotateマクロを使用することはあると思います。
数あるannotateマクロの中に、%system(hoge,hoge,hoge);があります。今回はそのお話
前にあげた<http://dengonmemo.blogspot.jp/2016/09/sas_29.html>と関連しています。
私も正しく理解しているかは怪しいところなので、間違っているかもしれませんです。

このマクロはannotateで文字やら線やらをグラフ内に書くときに、書く場所の設定をするマクロです。
そもそもsasで出したグラフには、data Area、Graphics Area、output Areaの3つがあります。
その三つを図で書くとだいたい下記のイメージです。(それぞれの斜線部分がそのAreaに対応)

data area(実際にグラフの値があるエリア)
|-----------------------|
|   |-----------------|   |
|   |                       |   |
|   |  ↑ /////////////    |   |
|   | |/////////////    |   |
|   | |/////////////    |   |
|   | |---→  |   |
|   |----------------  |   |
|                               |
|---------------------- |

Graphics Area(画面全体)
|---------------------|
|/////////////////////////|
|/|-----------------|///|
|/|/////////////////////|///|
|/|/ ↑/////////////////|///|
|/|/|////////////////|///|
|/|/|////////////////|///|
|/|/|---→//|///|
|/|/////////////////////|///|
|/|------------------|///|
|//////////////////////////|
|----------------------|

Output Area(全体からheaderとfooterを除いたところ)
|-----------------------|
|                               |
| |-------------------|   |
| |///////////////////////|   |
| |/↑////////////////////|   |
| |/|//////////////////|   |
| |/|//////////////////|   |
| |/|---→////|   |
| |///////////////////////|   |
| |-------------------|   |
|                               |
|----------------------- |

%systemの引数に1,2を指定するとData Area、3,4でGraphics Area、5,6でoutput Areaに
以降で使用するannotateマクロが出力されるようになります。
また1,3,5を指定すると百分率、2,4,6を指定すると座標で、以降のannotateマクロでの座標が指定できるようになります。

例えば%system(2,2,3)で、グラフのdata Areaの座標でannotateマクロを指定できます。
この下に%line( 1 , 30 , 1 , 28.5   , black, 1  , 0.15   );とすると
[1,30]から[1,28.5]に線を引きます。
%system(1,2,3)と記載した際、第一引数が1なので出力が百分率扱いなので、
この下のannotateマクロの指定で100より大きい値は指定できません。(100%が最大値)

また以下の様に一つのデータステップで複数回%systemは指定できます。
指定のたびに設定が切り替わります。
data anno;
    %system(2,2,3);
    *-----lineのX,Yは座標で指定できる;
    %line(~~);

  *-----lineのXは百分率(%)、Yは座標で指定できる;
    %system(1,2,2);

    %line(~~);
run;

%systemの第三引数は私も良くわかっていないので、今は扱っていません。
どなたか教えていただければ…

2017年2月3日金曜日

グラフの中の軸の範囲外の値を、はみ出ていることが分かるように出力する話

通常sasのgplotで出力したグラフは、軸に設定した値に収まらないデータがいる場合、
ログに範囲外のデータがいますよってnoteを出してくれます。
出してくれますが、出力したグラフを見てもどこが範囲外のデータなのかはわかりません。
今回ははみ出たデータをグラフにそれとわかるように出力するお話です。

data hoge;
    a = 1; Y = 2; output;
    a = 2; Y = 3; output;
    a = 3; Y = 4; output;
    a = 4; Y = 5; output;
    a = 5; Y = 3; output;
    a = 6; Y = 7; output;
    a = 7; Y = 4; output;
    a = 8; Y = 8; output;
    a = 9; Y = 4; output;
run;


*---------- 何の設定もしない場合;
proc gplot data = hoge;
    plot Y * A / vaxis = axis1 haxis = axis2 ;
    symbol1 c = black V = dot I = join;
    *---------- y軸目盛;
    axis1
      order = (1 to 5 by 1)
      origin=(10, 30)
      ;
    *---------- x軸目盛;
    axis2
      order=( 1 to 10 by 1 )
      origin=(10, 30)
    ;
run;

範囲外のデータがいますよのログ




グラフ


追加する設定は、symbolステートメントに追加された mode = include のことです。
*---------- 軸の幅を値が超えていたらはみ出るように設定;
proc gplot data = hoge;
    plot Y * A / vaxis = axis1 haxis = axis2 ;
    symbol1 mode = include c = black V = dot I = join;
    *---------- y軸目盛;
    axis1
      order = (1 to 5 by 1)
      origin=(10, 30)
      ;
    *---------- x軸目盛;
    axis2
      minor = none major = (w = 1.5)
      order=( 1 to 10 by 1 )
      origin=(10, 30)
    ;
run;



これではみ出たことがわかります。
はみ出るだけでなく、範囲外のデータを計算に含めることもできます。