昨年参加してからもう1年がたったことに驚きだが今年もPharmaSUGに参加した.今年はコロナもあってオンライン開催.昨年は前日に東京に入って準備やらしたのが懐かしい.家にいると気楽なのはいいのだが「ピンポーン」と誰か来るのはもはやご愛敬.残念午前はQAを見ないといけなかったので呼び出しに応じることはできず客は去っていった.用があるならまた来るやろ.準備にかこつけて普段会えない方と集まるのはいい機会ではあったのだがこんなご時世なので致し方ない.いややっぱり大都会東京のオサレお店でご飯食べたかった.大いに残念である.こんな時くらいしか東京行かないのに.
2020年12月1日火曜日
PharmaSUG2020 TOKYOに参加した話
2020年10月1日木曜日
マクロ変数が空であるかを条件にして分岐させる話
マクロ変数が空かそうでないかでプログラムを分岐できませんか?って聞かれました.
ちょっと具体的な状況がピンとこないところですが,とりあえず分岐だけはしたのでここに供養します.
最近sasを触らずsuper excel おじさんになっていたので良い気分転換です.
分岐の時にマクロ変数を空白と比較してあげると空かどうかの判定に使えます.以下で言う所の %if &test = %then %do ; ですね.
以下のプログラムでマクロ変数 testが空の時は空とログに出してくれますし,そうじゃない時はからじゃないよってログに出してくれます.
そう言えば近頃のsasでは%ifが平文で使えるので,いちいちマクロを定義して実行って形にしなくて良く見やすいプログラムがかけますね.
option mprint;
%let test=;
%if &test = %then %do ;
data _null_ ;
putlog "マクロ変数が空です" ;
run ;
%end ;
%if &test ^= %then %do ;
data _null_ ;
putlog "マクロ変数が空じゃありません" ;
run ;
%end ;
option nomprint ;
実行ログは以下の通りです.マクロ変数が空なことを示すメッセージのみがログに出ています.
460 option mprint;
461 %let test=;
462
463 %if &test = %then %do ;
464 data _null_ ;
465 putlog "マクロ変数が空です" ;
466 run ;
マクロ変数が空です
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
467 %end ;
468
469 %if &test ^= %then %do ;
470 data _null_ ;
471 putlog "マクロ変数が空じゃありません" ;
472 run ;
473 %end ;
474
475 option nomprint ;
このマクロ変数の戻り値に半角スペースって昔は通らなかったんですよね…いつか忘れましたが気づいたら通るようになっていました.便利になったもんです. 通らなかった時はマクロ変数をlength関数に入れて,戻り値が0だったらマクロ変数は空とする.みたいに書いていました.
2020年9月1日火曜日
32bit環境で作ったsasのformatを64bit環境にに移送する話
32bit環境で移行用のファイルを作成し,64bit環境で移行用ファイルを解凍します.移行には32bit環境での準備が要るっぽいので,format含めて移行が必要な場合は早めに準備しておいた方が良さそうですね...たまにcptファイルでデータを頂くことがあるので,その場合は以下の新環境で実行するプログラムを実行するとokです
エンコードの話とか怖くて触れたくない,出会いたくもない.ややこしいのが来ないよう日々祈るばかり.マジで勘弁してくれ
/*>>>>>---------- ここから旧環境で実行 ----------<<<<<*/
LIBNAME CAT32 "移行したいsasデータセットとsasのformatファイルのパス";
filename FILE64 '移行用ファイルを保存するパス\移行用ファイル名.cpt';
proc cport lib=CAT32 file=FILE64 ;
run ;
/*>>>>>---------- ここから新環境で実行 ----------<<<<<*/
libname CAT64 "移行後のデータセットを保存したいパス" ;
filename FILE64 "移行用ファイルを保存するパス\移行用ファイル名.cpt" ;
proc cimport lib = CAT64 file = FILE64 ;
run ;
2020年8月1日土曜日
SGPLOTでバタフライプロットを書く話
バタフライプロットとは以下のような真ん中から両端に向かって伸びる棒グラフです.見たことはありましたが先日初めて名前をしりました.
tables sex * age / out = V_CLASS ;
run ;
set V_CLASS ;
V_CNT = COUNT * -1 ; /*頻度を負の値に変換*/
V_SEX = 1 ;
end ;
V_CNT = COUNT ; /*頻度はそのまま*/
V_SEX = 2 ;
end ;
run ;
hbar AGE / response=V_CNT group = V_SEX barwidth = 1.0;
values=(-5 to 5 by 1) /*データ上は-5から5まで*/
valuesdisplay=("5" "4" "3" "2" "1" "0" "1" "2" "3" "4" "5") /*メモリの表示を指定*/
;
yaxis
values = (10 to 20 by 1)
grid /*格子線あった方が多分見やすい*/
;
run ;
2020年7月1日水曜日
defineのピナクルチェックのerrorですげーてこずった話
defineをピナクルでチェックすると以下のerrorが出ました.ほうほう参考資料が無いのねと思って確認すると,確かにdefineにリンク貼り忘れたものがあったので追加しても以下のerrorは消えなかったのです.
Pinnacle 21 ID:DD0015
Message :Referenced Document is missing
Severity :Error
Found :1
何で消えないのかわからなかったのでreportのdetailを見に行くと以下の通り.
最初から見に行けと言う話は横に置いて,error箇所はdefineの最終行,valuesはnullと何のことかさっぱりです.足りない参考資料は入れたので参考資料が無いよ!のnullではないのは明らかです.
Variables:Line Number: defineのソースコードの最終行
Values :null
正解はdefineの参考資料をリンクする際に記載するIDに誤記があったことでした.誤記していたためそんなID無いよ!ってerrorを出していたようです.
defineに参考資料をリンクする際には,最初の<def:SupplementalDoc>タグで参考資料のIDを定義して,本文中でそのIDを参照します.
正しい状態だと以下になります.leafIDが1回目と2回目でhogehogeと一致しています.
<def:SupplementalDoc>
<def:DocumentRef leafID="hogehoge"/>
</def:SupplementalDoc>
<def:DocumentRef leafID="hogehoge">
</def:DocumentRef>
今回のerrorの原因は以下の状態になっていました.
後半で指定したpiypiyoはSupplementalDocタグで指定していないです.
<def:SupplementalDoc>
<def:DocumentRef leafID="hogehoge"/>
</def:SupplementalDoc>
<def:DocumentRef leafID="piyopiyo">
</def:DocumentRef>
誤記をするなと言う話なのですが,末尾に1つだけerrorを返すのではなくせめて一致しないIDの数くらい教えてほしいです…今回は誤記があったのが3つだったので,最低でも3つはあったはずです…1つしかerrorはないって言われていたので,defineの中で1つしかなさそうなものからerrorの原因を探していました…
2020年6月15日月曜日
sgplotでemfファイルを出力する話
sas9.4のsgplotで出力をemfファイルで出したい時の設定です.いっつもpngとかで出しがちなので覚えてないんですよね…emfにもいいところはあるのですが.
以下プログラム
/*----- 適当なデータ -----*/data hoge ;
call streaminit(1234) ;
do X = 1 to 36 by 1 ;
Y = int(rand("uniform") * 100) ;
output ;
end ;
run ;
ods html close ; *--htmlをcloseしないとwarninig出る;
ods listing gpath = "hogehoge" ;
ods graphics on / reset = all imagename="hist1" imagefmt=emf ;
proc sgplot data = hoge nowall noborder ;
vbar X / response = Y ;
xaxis
values = (1 to 25 by 1)
label="発現時期"
;
yaxis
label="発現率(%)"
values = (0 to 100 by 20)
;
run ;
ods graphics off ;
ods listing close ;
ods html ; *-- 元に戻す ;
2020年6月1日月曜日
複数の文字変数をつないだら文字切れするのを回避する話
コロナで生活リズム変わったからね仕方ないね
フリーテキストのコメントを一覧表かなんかに出力する時に,想定より長いコメントが来て途中までしか出力出来てなかったことがありました.一覧表と言えばページ数がかさむので,途中で切れてないか目視チェックは結構厳しいところがあります.安易に変数長を200byteまでにすると200を超える長さのコメントが来るとか,出力の際に()付けたりとか複数のコメントを結合させて1か所に出せとか言われるとぽろっと後ろが切れたりします.お薬の英語名と日本語名と記載名とかもそうですが…
/*----- 元のコメント -----*/
A = "日本語のコメントだよ" ;
B = "qwertyuiop";
length OUT $24 ;
OUT = A || "/" || B ;
V_A = lengthn(A) ;
V_B = lengthn(B) ;
V_OUT = lengthn(OUT) ;
if V_A + V_B + 1 > V_OUT then putlog "E" "RROR/" _n_ ;
run ;
241
242 data _null_ ;
243
244 /*----- 元のコメント -----*/
245 A = "日本語のコメントだよ" ;
246 B = "qwertyuiop";
247
248 length hoge hoge2 hoge3 $24 ;
249 hoge = cat(A, "/" , B) ;
250 hoge2 = cats(A, "/" , B) ;
251 hoge3 = catx("/" , A , B) ;
252
253 run ;
正しい結果には31文字が含まれますが、実際の結果は、呼び出し環境によって、24文字に切り捨てられた、またはすべてブランクの可能性があります。
どの引数以降が切り捨てられたかを次に示します。
NOTE: 第3引数(関数CAT('日本語のコメントだよ','/','qwertyuiop'):行 249 カラム 8)は無効です。
WARNING: CATS関数の呼び出しで、結果に割り当てられたバッファの長さが十分ではなかったため、すべての引数を連結して含めることができませんでした。
正しい結果には31文字が含まれますが、実際の結果は、呼び出し環境によって、24文字に切り捨てられた、またはすべてブランクの可能性があります。
どの引数以降が切り捨てられたかを次に示します。
NOTE: 第3引数(関数CATS('日本語のコメントだよ','/','qwertyuiop'):行 250 カラム 9)は無効です。
WARNING: CATX関数の呼び出しで、結果に割り当てられたバッファの長さが十分ではなかったため、すべての引数を連結して含めることができませんでした。
正しい結果には31文字が含まれますが、実際の結果は、呼び出し環境によって、24文字に切り捨てられた、またはすべてブランクの可能性があります。
どの引数以降が切り捨てられたかを次に示します。
NOTE: 第3引数(関数CATX('/','日本語のコメントだよ','qwertyuiop'):行 251 カラム 9)は無効です。
A=日本語のコメントだよ B=qwertyuiop hoge= hoge2= hoge3= _ERROR_=1 _N_=1
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.01 秒
CPU時間 0.01 秒
2020年4月1日水曜日
includeで読み込んだプログラムファイルのパスとファイル名を取得する話
変数の名前はSYSINCLUDEFILEDIR とSYSINCLUDEFILENAME です.長いので覚えられないですね.これをプログラムに仕込んでおいて,その仕込んだプログラムをincludeすると値が取得できます.平文で書いてもマクロ変数の中身は空なのでincludeしている時に値を取得している感じですかね.errorにならないのはとても良い
例えば以下の簡単なプログラムをtst.sasと名前を付けてincludeすると,ログにプログラム名とパスが表示されます.表示されるんですが...使い道思いつかないですね...ファイル名に関しては実行しているプログラム内で自分のファイル名を取れるのでそこは便利か...?
/*---------- includeしたプログラム(ファイル名はtst.sas) ----------*/
/*読み込み成功*/
%put &=SYSINCLUDEFILEDIR ;
%put &=SYSINCLUDEFILENAME ;
/*---------- include ----------*/
data _null_ ;
rc = dlgcdir("piyopiyo") ;
run ;
%include "tst.sas" / source2;
/*---------- 実行ログ ----------*/
144 data _null_ ;
145
146 rc = dlgcdir("piyopiyo") ;
147
148 run ;
NOTE: 現在の作業ディレクトリは"piyopiyo"です。
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.01 秒
CPU時間 0.01 秒
171
172 %include "tst.sas" / source2 ;
NOTE: %INCLUDE (レベル1)ファイルtst.sasはファイルpiyopiyo\tst.sasです。
173 +/*読み込み成功*/
174 +%put &=SYSINCLUDEFILEDIR ;
SYSINCLUDEFILEDIR=piyopiyo /*---------- includeしたプログラムのパス ----------*/
177 +%put &=SYSINCLUDEFILENAME ;
SYSINCLUDEFILENAME=tst.sas /*---------- includeしたプログラムの名前 ----------*/
あと同じようなものにSYSINCLUDEFILEDEVICE とSYSINCLUDEFILEFILEREF もあります.
includeしたファイルが存在するデバイス名と,includeにfilenameステートメントで定義した文字列を指定した時に,そのfilerefを取得するものです.今回はfilenameしてないので空ですね
175 +%put &=SYSINCLUDEFILEDEVICE ;
SYSINCLUDEFILEDEVICE=DISK /*-------- ファイルはdiskにいる,それはそうだ. --------*/
176 +%put &=SYSINCLUDEFILEFILEREF ;
SYSINCLUDEFILEFILEREF= /*---------- 今回は空 ----------*/
filename hogehoge "hoge.sas" ;としてから%include hogehogeを実行すると,SYSINCLUDEFILEFILEREFの値としてhogehogeが取れます.filefilerefってfileが続くのちょっとややこしい
2020年3月1日日曜日
棒グラフをsgplotで出す話
sgplotで棒グラフを書く時のサンプルです.vbarステートメントを使って出力するのですが,詳細は以下のプログラムの通りです.あんまり凝ったことしてなくほんとにただの紹介なのであまり目新しいことはないですが...軸ラベルが適当ですみません
変数Yの平均値を書いているのですが,オプションでmeanを指定すればOKなのと,標準偏差のヒゲをはやしているのですがこれもオプションで書けます.わざわざ出力用データセットに平均値と標準偏差を持たなくて良いのは楽ですね.確認の具合もあるので何でもかんでもオプションで出せばいいという訳ではありませんが…データに持たせた標準偏差を使ってヒゲをannotateで書かそうとする奴は敵です.
/*以下プログラム*/
data HOGE;
call streaminit(12);
do i = 1 to 10 ;
Y = int(rand('uniform') *100) ;
if 1 <= i <= 5 then GR = 1 ;
if 6 <= i <= 10 then GR = 2 ;
output;
end;
run;
ods graphics / imagename="bar" imagefmt=png ;
ods listing gpath = "hogehoge" ;
ods html close ;
proc sgplot data = hoge noautolegend nowall noborder ;
styleattrs datacolors = (gray white) ;
vbar GR / group = GR groupdisplay = cluster
response = Y stat = mean nozerobars /*Yの平均値の棒を立てる*/
barwidth = 0.5
limits = upper limitstat = stddev /*Yの標準偏差のひげを生やす*/
;
xaxis type=DISCRETE ; /*不要*/
run ;
ods graphics / reset = all ;
ods html ;
2020年2月1日土曜日
現在の作業ディレクトリの変更する関数の話
正しく実行できると戻り値は0になります.
415 /*現在の作業ディレクトリをlogに表示*/
416 data _null_;
417 rc=dlgcdir(); /*()を空にして実行すると現在のディレクトリを表示する*/
418 put rc=; /*正しく実行できているかの確認_別に不要ではあるが見るのには便利*/
419 run;
NOTE: 現在の作業ディレクトリは"piyopiyo"です。
rc=0 /*正しく実行できているので戻り値が0*/
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
420
421 /*現在の作業ディレクトリをhogeに変更*/
422 data _null_ ;
423 rc = dlgcdir("hoge") ; /*()に指定したフォルダを現在のディレクトリとする*/
424 put rc= ;
425 run ;
NOTE: 現在の作業ディレクトリは"hoge"です。
rc=0
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
現在のディレクトリを変更することで,指定したフォルダ内のプログラムを%incで読み込む際にファイル名の指定だけで済むので記述が短くなって良いですね.もちろん現在のディレクトリを変更しているので,何が指定したフォルダに出力されるかを確認する必要はありますが.
例えば指定したフォルダの中のhoge.sasとhoge2.sasを実行するには%incにファイル名を書くだけでokになります.もちろん実行するプログラムの前にフォルダパスを記載すれば指定していないフォルダのプログラムも実行できますが,タラタラ前に書くのがめんどくさい時もありますし,フォルダパスをマクロ変数に格納して何かのはずみでマクロ変数の上書きが意図せず起きたりするのが結構ややこしい印象です.
%inc "hoge.sas" ;
%inc "hoge2.sas" ;
私は使ったことないですけど便利そうですよね,そのうち使うかもしれません.
後はファイルメニューの「プログラムを開く」で,最初に表示されるファイルの場所が現在のディレクトリになれば最高なんですが…今はsasの保存場所かなんかが最初に出るんですよね…最初と言わずとも現在のディレクトリにすぐアクセスできればokなんですが.
2020年1月8日水曜日
sas studioが9.4M6に更新されてて嬉しい話
復旧したのでとりあえずproc product_statusを実行すると,BASE SASが9.4M6に更新されているじゃないですか.これで思う存分円グラフが試せるというもんです,やったぜ.円グラフの実用性については知りませんねえ…
毒にも薬にもなりませんが更新されててとてもうれしい.せっかくなので該当箇所を赤文字にしています.意味などないですが.
1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
70
71 proc product_status ;
72 run ;
For Base SAS Software ...
Custom version information: 9.4_M6
Image version information: 9.04.01M6P110718
For SAS/STAT ...
Custom version information: 15.1
For SAS/GRAPH ...
Custom version information: 9.4_M6
For SAS/ETS ...
Custom version information: 15.1
For SAS/OR ...
Custom version information: 15.1
Image version information: 9.04.01M6P050819
For SAS/IML ...
Custom version information: 15.1
For SAS/QC ...
Custom version information: 15.1
For SAS/CONNECT ...
Custom version information: 9.4_M6
For SAS Enterprise Miner ...
Custom version information: 15.1
For SAS Time Series Workspace Macros ...
Custom version information: 15.1
Image version information: 9.04.01M5P110718
For SAS/ACCESS to Postgres ...
Custom version information: 9.4_M6
For SAS Integration Technologies ...
Custom version information: 9.4_M6
For SAS/Secure 168-bit ...
Custom version information: 9.41_M3
For SAS Credit Scoring ...
Custom version information: 15.1
For SAS Text Miner ...
Custom version information: 15.1
For SAS High-Performance Forecasting ...
Custom version information: 15.1
For High Performance Suite ...
Custom version information: 2.2_M7
For SAS Forecast Server Mid-Tier ...
Custom version information: 15.1
Image version information: 9.04.01M5P110718
For SAS/ACCESS Interface to PC Files ...
Custom version information: 9.4_M6
For SAS/ACCESS Interface to MySQL ...
Custom version information: 9.4_M6