LAG関数の挙動には注意が必要です。
以下のプログラムを実行してみて、予想した結果になるか見てみましょう。
*** サンプルデータ作成 ; data DT1; do X = 1 to 5; output; end; run; *** 例1: 2個前の値をとってくる ;
data OUT1;
set DT1; Y = lag2(X);
run;
data OUT2; run;set DT1; if X ^= 4 then Y = lag2(X);
|
例1は予想通りだと思いますが、例2はどうでしょう?
結果の赤文字で示した部分が「3」になると思ってたら要注意です。
解説
そしてこの関数、1つ面白い性質があります。
この関数が実行されるとき、
第1引数の条件式の結果がなんであろうと、第2・第3引数は、内部で両方とも処理(計算)が行われているようです。
つまり今回の 「ifn( X^=4, lag2(X), . )」 は、
条件式「X^=4」の結果がTRUEだろうがFALSEだろうが、内部では毎回こっそり第2引数の「lag2(X)」が実行されています。
解説
ここから、別記事「LAG関数の動き」で紹介したイメージをもとに説明するので、この別記事を読んでいないと分かりづらい部分あるかも。
まずは以下、「Y = LAG2(X)」と書いたときの内部処理のイメージです。
(自分なりの解釈になっている可能性があるかもしれませんので、あしからず・・)
まず、LAG関数によって内部で「キュー」と呼ばれる仕組みを利用しています。
続いて、「if X ^= 4 then Y = lag2(X)」というように、IFステートメントと組み合わせたときの内部処理のイメージ。
(こちらも自分なりの解釈になってる可能性あり)
LAG関数が実行されないと、キューの中身が更新されないことによるものですね。
ここでもし、「IF条件が通った時だけ、2行前の値を取ってきたい」という場合は、以下のようにLAG関数が毎回実行されるように工夫します。
data OUT3; drop Y2;set DT1; Y2 = lag2(X); if X^= 4 then Y = Y2; run;
|
ここからちょっとした裏技を紹介。
上記の処理は、LAG関数とIFN・IFC関数を組み合わせることによって、より簡潔に書くことが出来ます。
解説
上記の処理は、LAG関数とIFN・IFC関数を組み合わせることによって、より簡潔に書くことが出来ます。
data OUT3; set DT1; Y = ifn( X^=4, lag2(X), . ); run;
|
解説
IFN・IFC関数の構文は以下の通り。
IFN( 条件式 , 条件がTRUEの場合の戻り値 , 条件がFALSEの場合の戻り値 ) ・・・ 戻り値が数値の場合はIFN、文字の場合はIFC関数を使います。 |
そしてこの関数、1つ面白い性質があります。
この関数が実行されるとき、
第1引数の条件式の結果がなんであろうと、第2・第3引数は、内部で両方とも処理(計算)が行われているようです。
つまり今回の 「ifn( X^=4, lag2(X), . )」 は、
条件式「X^=4」の結果がTRUEだろうがFALSEだろうが、内部では毎回こっそり第2引数の「lag2(X)」が実行されています。
毎回LAG関数が実行されることで、2行前の値を取ってくることができているわけです。
この性質、他にも使えそうですね。なんか思いつきそうで思いつかないですが。
この性質、他にも使えそうですね。なんか思いつきそうで思いつかないですが。
"内部処理のイメージ"の図が非常に理解するのにありがたかったです。またifnの内部挙動の性質もディープで(笑)、いいことを教えて頂きました。ありがとうございました。
返信削除コメント有難うございます!
返信削除LAG関数のこの辺の動きはわりと間違えやすい部分で、私自身も昔痛い目をみました。
このマニアックな内容の記事がお役に立てて良かったです!