http://sas-tumesas.blogspot.jp/2013/12/do-untilendset-end1.html
で、do loopの中にsetコマンドを突っ込むやりかたを紹介しました。
また、その方法については「SASインタリーブ(interleave)の紹介と再帰的インタリーブで、SQL再マージ処理をデータステップで疑似的に表現する」
http://sas-tumesas.blogspot.jp/2014/01/sasinterleavesql.html
でも少しふれましたし
最近、「詰めSAS10回目_変数内の1文字ごとにオブザベーションを起こす」でa matsuさんが
提案してくれた方法もdo ループとsetをつかっています。
http://sas-tumesas.blogspot.jp/2014/01/sas101.html
で、これとほぼ同じ内容にはなるのですが
ループの中でカウンタとする変数を増加する場合、
ループの中で変数+1と割り当てる方法があるのですが、最近、それを省略してもかけるんじゃないかと思いつきました。
ちょっと細か過ぎて、この話題で喜ぶ人がどれくらいいるか謎ですが、
たとえば
data Q1;
X='A';output;
X='A';output;
X='Z';output;
X='B';output;
X='Z';output;
X='A';output;
X='B';output;
X='C';output;
X='Z';output;
run;
こういうデータがあって、
Xの値に「Z」が出現するまでのオブザベーション数をカウントし、出現した行の番号と
ともに出力するというプログラムをかくとします。
求めたい結果は
元データの3,5,9行目でZが出現しているのでROWには3,5,9が入り、
そこまでに出現するZ以外の文字のカウントがCOUNTに入ります。
さて、どう切り込みますか?
今回の場合、元データの格納順を崩せないので
ソートを利用したfirst last系の分岐を利用できないんですね。
多分、第一感はretainだと思います。
data A0;
set Q1;
retain COUNT 0;
COUNT+1;
if X='Z' then do;
ROW=_N_;
output;
COUNT=0;
end;
drop X;
run;
で詰みですね。
これでも全然いいんですが、do loopを使うなら
data A1;
do COUNT=0 by 1;
set Q2;
ROW=monotonic();
if X='Z' then leave;
end;
drop X;
run;
これでも詰みなんです。
do loopの to条件を省くことでループ変数そのものをカウンタ変数として使っちゃうわけですね。
setがループされるため、ここで_N_つかっても1,2,3とはいるだけで元データの行番号をとるうえではポンコツなのでmonotonic関数でとります。
ちなみにここでのleaveはoutputでもいいです。leaveでもオブザベーション起きるのが面白いので
leaveにしてます。
ちなみにifで抜けなくても、until終了条件でも当然OK
data A2;
do COUNT=0 by 1 until(X='Z');
set Q2 end=eof;
ROW=monotonic();
end;
drop X;
run;
0 件のコメント:
コメントを投稿