実践で使用する機会がそれほど多いとは思いませんが、たまにあったり、また直積を作った方がスムーズに以後の処理ができることもあります。
問題は
data Q1;
input A B;
cards;
1 2
3 4
5 6
;
run;
【データセットQ1】
data Q2;
input C $ D $;
cards;
A B
C D
E F
;
run;
【データセットQ2】
の二つから
のようなデータセットを作ることです。
【解法1】
data A1;
set Q1;
do i=1 to Q2OBS;
set Q2 nobs=Q2OBS point=i;
output;
end;
run;
まずはデータステップで詰みです。nobs=オプションはデータセットの総obs数をとれるのですが
それをsetステートメントの前に使用できるというのは意外です。それをループ終点にして
point=でダイレクトアクセスする度に明示的にOutputすることで、Q1のSetによって、Q1が1obs読まれる度にi=1からQ2の最後のobsまでOutputされ、それがQ1のSetが全obs完了するまで行われるので結果として直積が作成されます。2つのデータセットのサイズによって変わりますが
基本的にはこれが最も効率の良い作成法だと思われます。コードもコンパクトにまとまってます。
【解法2】
proc sql noprint;
create table A2 as
select *
from Q1,Q2;
quit;
直積はSQLの基本ともいえるので(単純結合というぐらいですし)、SQLで詰ませます。
cross join等の方が綺麗な書き方なのかもしれませんが、とりあえず一番単純な書き方で実現です。SQLを使う場合の注意点は、ログにnoteとしてデカルト積が生成されたことを知らせるメッセージが必ずでるので、ログの内容に厳格に注意を払う仕事では留意する必要があります。
【解法3】
data A3;
if _N_=0 then do;
set Q1 Q2;
end;
if _N_=1 then do;
declare hash hq(dataset:'Q2');
declare hiter hi('hq');
hq.definekey('C','D');
hq.definedata('C','D');
hq.definedone();
end;
set Q1;
rc=hi.first();
if rc=0 then output;
do while(rc=0);
rc=hi.next();
if rc=0 then output;
end;
drop rc;
run;
ハッシュ反復子でやってみました。ハッシュはメモリにデータを展開するので、作成が高速化するか
と思ってやったのですが、コードが悪いのか、いくつかテストした条件ではデータステップやSQLの
1.5~2倍遅い結果しかだせていません。効率悪いはコードは長くて意味不明だわでいいとこなしな
感じですが、恐らくQ1がかなり巨大でQ2もそこそこの大きさのデータセットにして、オプションで
ハッシュの割当サイズを適度にすれば、速くなったりする気がします。いや、そもそも直積にハッシュはあまり意味がないのか。すみません、勉強中です。
0 件のコメント:
コメントを投稿