monotonic関数でアイタタタ

monotonic関数は超便利です。
SQLプロシジャの中でいわゆるrow_number的、SASで言うなら_N_的な処理ができる(ちょと違うけど)。
通常のデータステップでも、例えば、3,5,8オブザベーションを抽出って時に

where _N_ in (3,5,8)って書き方はできないから
if _N_ in (3,5,8) になるけど、データを絞る場合サブセットifよりwhereの方が
効率的なわけで、where使いたいな~って思うんだけど

monotonic関数なら

where monotonic() in (3,5,8)で実現できてしまう。

もちろん、プロシジャに流すデータセットも絞れる優れもの。
proc print data=XX;
where monotonic() in (3,5,8)
run;

そんな手軽さもあって日ごろ愛用しているですが、この関数はちょっと色々と癖というか謎がありまして、
そのことについてはSAS忘備録のa.matsuさんが注意喚起してくれています。
http://sas-boubi.blogspot.jp/search/label/%E9%96%A2%E6%95%B0%3A%20MONOTONIC

今回はそこに注意事項を追加することになりそうです。


いや、monotonic関数については完全に把握している、複雑な処理じゃなきゃ問題ないでしょって驕っていたせいで原因箇所の特定にかなりてこずってしまいました。
生兵法は大怪我のもとってやつですよ。ほんと。

以下のようなデータセットがあり

data Q1;
do x = 1 to 10;
output;
end;
run;




















まずは以下を実行

data A1;
set Q1;
where monotonic() >= 3;
run;
















問題なし。

次に以下を実行

data A2;
set Q1;
where monotonic() <= 6;
run;














問題なく、狙い通り。

じゃあ次は上記二つをあわせて、3~6を抽出してみましょう

data A3;
set Q1;
where 3 <= monotonic() <= 6;
run;














なんで、7とか8が入ってくんの!?

ヒントはログの
NOTE: データセット WORK.Q1 から 6 オブザベーションを読み込みました。
      WHERE (3<=MONOTONIC()) and (MONOTONIC()<=6)」という記述です。
これは、where 3 <= monotonic() <= 6が実行時にSASによって
 WHERE (3<=MONOTONIC()) and (MONOTONIC()<=6)と直されて実行されたことを示します。


当然以下も同じ結果でアウト

data A4;
set Q1;
where 3 <= monotonic() and monotonic() <= 6;
run;

さて、アホな僕は何が起きたかすぐにはわかりませんでしたが、
聡明なみなさんはこのカラクリに既に気がついてますね?


whereステのmonotonicはそこが実行された時点からカウント再スタートな感じで、次のmonotonicはその時点からのカウントなんですね。
つまり3オブザベーション目も含めて6オブザベーション取得するから上記の結果になってるわけですよ。

なるほどね。関数実行時に動的に値が決まるのか、その決まり方を僕がわかってなかったんですね

つまり以下のように書けばいいのか

data A5;
set Q1;
where monotonic() between 3 and 6;
run;











betweenが嫌いならinで書いてもよし

data A6;
set Q1;
where monotonic() in ( 3 : 6 );
run;

なるほどね~。
しかし、これは危ないな。

where 3 <= monotonic() and monotonic() <= 6;

where monotonic() between 3 and 6;

とで結果が違うんだもんなぁ。

僕がSASの試験問題マニアックに作るなら入れたいような問題ですね

0 件のコメント:

コメントを投稿