ifn(ifc)関数の留意点。偽のルートも全部内部で計算されてるからねって話

うっかりしていると2017年も大晦日!
ちょっとブログのサボり癖がついてしまいそうで、このままじゃいかんので更新します。
来年はもうちょっと頑張ります。

たいしたネタじゃないですが、大分前に下書きしてた以下の記事。

=============================

ifn関数便利です。結構使います。
SQLでも使えるし、なかなか良いやつですね。

ただ、ちょっと注意なのがIfステートメントと内部処理の違いを
ちゃんと知ってはいてねということです。

例えば以下のコード。

data a;
X="A";Y=.;output;
X="B";Y=1.;output;
run;

data b;
set a;
A=sum(Y,1);
Z=ifn(X="A",1,Y+1);
run;















結果は全く問題ありません。
ところがログには「欠損値を含んだ計算により‥」とでます。
Zには欠損なんてないのに。

つまりIFN関数は、先に引数を全部計算してから、条件分岐で
どっちを採用するかを選択しているわけです。
結果的に通らないルートも全部処理しちゃうんですよ。
Ifステートメントは、真の場合のみthen以下の処理がおきるので、そこが大きな
違いです。

例えば、処理時間のめっちゃかかる計算の例として、たらいまわし関数を例にだすと
ifステートメントとifn関数で処理時間が何十倍も変わってきたりするわけですね。
以下がコードですが、ifステートメント0.55秒に対してifnだと54.75秒かかってます。

proc fcmp outlib=WORK.FUNCDT.CARCALC ;
  function takf(x, y, z);
  if x <= y then
    return(z);
  else
    return (takf(takf(x - 1, y, z), takf(y - 1, z, x), takf(z - 1, x, y)));
  endsub;
run;
options cmplib=WORK.FUNCDT;


data q1;
do i = 1 to 100;
output;
end;
run;

data a1;
set q1;
if _N_=50 then  A= takf(18, 9, 0);
run;

data a2;
set q1;
A= ifn(_N_=50,takf(18, 9, 0),.);
run;










ちなみに、この性質を逆手にとって、相変わらずぶっ飛んだアイデアを公開している人がいるので紹介しておきましょう。

「LAG関数とIFN / IFC関数のコンボ技」
http://sas-boubi.blogspot.jp/2015/03/lagifn-ifc.html