482 Views
March 29, 24
スライド概要
[第2回大阪sas勉強会] 森岡裕
SAS言語を中心として,解析業務担当者・プログラマなのコミュニティを活性化したいです
DOSUBL関数とハッシュオブ ジェクトの素敵な関係 DS2におけるSQLとHASHの蜜月関係をデータステップでも実現したい たとえそれが見せかけの愛に過ぎなくても
【前提知識】 100万回:「大半のソートは百害あって一利無しという話」 http://sas-tumesas.blogspot.jp/2016/04/blog-post.html 僕の頁:「dosubl関数(call executeの兄弟) 」 http://sasboku.blog.fc2.com/blog-category-37.html SAS忘備録:「データステップ内でプロシジャを実行する。」 http://sas-boubi.blogspot.jp/2016/05/blog-post_17.html
%macro get(master=,key=,var=,flg=);
%let name = &sysindex;
%let qkey = %sysfunc( tranwrd( %str("&key") , %str( ) , %str(",") ) );
keyが一意になっていることを前提として、他の
if 0 then set &master(keep= &key &var);
データセットから値を取得するマクロ%get
if _N_=1 then do;
declare hash h&name.(dataset:"&master(keep= &key &var)", duplicate:'E');
keyが一意になってなくても動き、keyが存在する
h&name..definekey(&qkey);
かをYNで返すマクロ%chk
h&name..definedata(all:'Y');
h&name..definedone();
この2つのマクロがあれば、例えばADSLなどは
end;
ほぼ1ステップで作成可能。
if h&name..find() ne 0 then do;
call missing(of &var);
%if %length(&flg) > 0 %then %do;
&flg="N";
%macro chk(master=,key=,flg=);
%end;
%let name = &sysindex;
%let qkey = %sysfunc( tranwrd( %str(“&key”) , %str( ) , %str(“,”) ) );
end;
if 0 then set &master(keep= &key);
else do;
if _N_=1 then do;
%if %length(&flg) > 0 %then %do;
declare hash h&name.(dataset:”&master(keep= &key)”, multidata:’Y’);
h&name..definekey(&qkey);
&flg="Y";
h&name..definedone();
%end;
end;
end;
&flg = ifc(h&name..check()=0,”Y”,”N”);
%mend chk;
%mend get;
data adsl(label=""); set sdtm.dm; VISIT=“Day 1”; %lookup(master=EX,key=USUBJID VISIT,var=EXDAT) TRTSDT=input(EXDAT,?? Yymmdd10.); CMCAT="CONCOMITANT MEDICATION"; %chk(master=cm,key=usubjid cmcat,fl=CMFL); ・・・・・・・・・・・ run;
duplicate:‘E‘は、やはり保険としてつけておきたい。 しかし、masterに指定する際に、ターゲットにしたいkeyについて、 まさに該当するデータでは一意にしかならないが、 データセットの構造上では一意にしきれない状態が発生した際に困ること があった。 VSTESTCD="HEIGHT“; VSBLFL=“Y”; %lookup(master=vs,key=USUBJID VSTESTCD VSBLFL,var=VSSTRESN) HEIGHTBL=VSSTRESN; ★上記のコードについて、ベースラインフラグがたっているデータは USUBJIDとVSTESTCDで一意なので、一見問題なさそうだが、 duplicate:‘E‘に ひっかかる。→ VSBLFLがnullの場合、一意にならない。データセット自体が 上記3変数で一意にならないから。
proc ds2 libs=work; data adsl(overwrite=yes); declare package hash h1(); dcl double HEIGHTBL; method init(); h1.dataset('{select USUBJID,VSSTRESN as HEIGHTBL from vs where VSBLFL=''Y'' and VSTESTCD=''HEIGHT''}'); h1.keys([USUBJID]); h1.data([HEIGHTBL]); h1.definedone(); DS2ならdatasetメソッドにSQLの抽出結果をとれるので、 end; 楽なんだが‥ method run(); set dm; 全部DS2でコーディングするのはちょっとしんどい。 h1.find(); end; enddata; →データステップで同じことがしたい run; でもSCL関数は難しいから使いたくない。 quit; →今までは一度抽出したサブセットを作成してからそれ に対して%getをかけていた
今回、dosubl関数でviewを作成すれば、declareステートメントのdataset:で指定するソースに間に 合ってしまうということを発見したわけです。 data adsl; set dm; if 0 then set vs; もろもろの細かい注意点や挙動は口頭で話します。 以上 if _N_=1 then do; drop rc; rc=dosubl("proc sql ; create view temp as select USUBJID,VSSTRESN from vs where VSBLFL='Y' and VSTESTCD='HEIGHT'; quit;"); call execute("proc sql noprint; drop view temp; quit;"); declare hash h1(dataset:"temp“,duplicate:’E’); h1.definekey("USUBJID"); h1.definedata("VSSTRESN"); h1.definedone(); end; if h1.find() ne 0 then call missing(of VSSTRESN); run;