do to by ループのtoを消してもループは成立するので、それを使って1手得を狙っていく話

以前、「do until(end変数)set end=を利用して、複数のデータステップを1つにまとめて共存させる方法」
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 件のコメント:

コメントを投稿