MAXをとるためにORDINALを使う屁理屈

実戦用というよりかは
頭を柔くするパズル感覚、昔やってた「詰めSAS」的な話として見てください。

さて、以下のデータセットがあって、

data A;
X1=1; X2=3 ;X3=2;output;
X1=.;  X2=.  ;X3=2;output;
X1=3; X2=.  ;X3=3;output;
X1=.;  X2=.  ;X3=.;output;
run;









MAXをとれと言われれば一目、こう書きます。

data B;
set A;
 M=max( of X: );
run;









しかし、NOTEがでます。










NOTEを回避するには

data C;
set A;
 if n(of X:) ne 0 then M=max( of X: );
run;

と書くわけですが、結局、引数が全欠損の場合、いずれにせよ
結果は欠損で変わらない。

そうすると、NOTEの有無を除けば「 if n(of X:) ne 0 then 」の部分は完全な無駄手、
結果は同じなのに一手損しているようで気持ち悪いなぁと昔から思っていました。

個人的な感性の話を抜きにしても、
min maxが入れ子になっているとき、かつ各ブロックで全欠損が生じる可能性が許容されている場合、別に出てもいいNOTEを回避するためだけに、いちいち、分解して書かないといけなかったりして面倒なこともあります。

これ、実は以下のように書けば、ifを書かずにNOTEもださずに、同じ結果に
なると思うんですね。

data D;
set A;
 M=ordinal( 3 , of X: );
run;

ordinal関数は、欠損値を含めて、n番目に小さい数をとるという関数です。
nを引数の数に合わせることで、最終番目に小さい数、すなわちそれが最大値という理屈です。

はなから欠損値を含めることを想定した関数なので、引数が全欠損でも仕様範囲内なのでNOTEはでない。
同値があっても、引数の数を指定していれば結果は揺らがない。

最大をとるために、あえて逆に小さい方からみるっていう発想が頭の体操になるなぁと。

対象引数リストが配列なら、ordinalの第一引数にはdim関数を入れちゃえば、より安心なコードになるね。



0 件のコメント:

コメントを投稿