ラベル lag の投稿を表示しています。 すべての投稿を表示
ラベル lag の投稿を表示しています。 すべての投稿を表示

IFステートメントにおけるLAG関数の挙動の話

明けましておめでとうございます。今年もよろしくお願いします。

さて、以前IFステートメントでlag関数を使うときは注意が必要といったことを書いたような気がしますが、具体的にどういうことなのかを書きます。

実はSASのHPに同じことが書いているんですが、、申し訳ないけど、
いや、はっきり言ってわかりにくい!
http://www.sas.com/offices/asiapacific/japan/service/technical/faq/list/body/ba096.html


例えば以下のようなデータセットがあったとします。

data Q1;
X=1;output;
X=3;output;
X=2;output;
X=4;output;
X=5;output;
X=0;output;
X=6;output;
run;













今、やりたい処理が

「Xの値が3未満の場合、ひとつ前のXの値をYという変数に入れる」
という処理の場合、

data A1;
 set Q1;
 if X<3 then Y=lag(X);
run;

と書いてしまいそうなのですが、結果は












見当違いの悪手失着です。
あれ?一つ前だから、3obsは3,6obsは5じゃないの??といった感じですが、
実は上記のコードで実現されたのは
「Xの値が3未満の場合、ひとつ前にXが3未満であったときの値をYという変数に入れる」

という処理です。つまりIF条件式を通過したobsをカウントして、lagなら1つ前、lag2なら2つ前というように考えるのです。


挙動さえ理解していれば、条件に合致した前の値をとるといった処理が書きたい時に

data A0;
 set Q1;
 retain Y_;
 if X<3 then do;
  Y=Y_;
  Y_=X;
 end;
 drop Y_;
run;

のように第一感で浮かぶretainステートメントを使う必要もなく、コードがコンパクトになります。


ちなみに、最初に書いた「Xの値が3未満の場合、ひとつ前のXの値をYという変数に入れる」
をやりたい場合は

data A1;
 set Q1;
 Y_=lag(X);
 if X<3 then Y=Y_;
 drop Y_;
run;




のように、一度単純にlag関数を使って値を割り当ててから、IFします。








DIF関数とLAG関数_lag2(x)とlag(lag(x))は同じだけどdif2(x)とdif(dif(x))は違うみたいな話

DIF関数、最近まで知りませんでした。1つ前のオブザベーションの値と今の値との差を返す関数で、dif(x)はx-lag(x)と同義だそうです。
LAG関数は1つ前のオブザベーションの値を返します。lag2(x)とすれば2オブザベーション前のxの値,lag3(x)なら3つ前といったようにlagの後の数字を変えることで調整が効きます(ただし負の値で先のオブザベーションの値をとったりはできませんので、はい残念)
lag2(x)はlag(lag(x))と同じです。1つ前の1つ前は2つ前というわけです。
(脱線ですがlagはif文の中に直接記述すると正しく機能しない性質があるので条件式に使いたい場合は一度割り当てステートメントで新規変数に入れてからそれを使いましょう。知らないと非常に追いにくいエラーの代表的な例です)

ではdif(dif(x))はどんな値を返すのか?また、dif(lag(x))やlag(dif(x))はどんな意味なのか?
それを見てみましょう。

適当にデータセットを作ります。

data Q1;
do i=1 to 10;
 X=ceil(ranuni(777)*20);output;
end;
drop i;
run;


これに対して以下のプログラムを実行します。
頭の体操が好きな方は、結果を予想してからどうぞ。

data A1;
 set Q1;
  DIFX=dif(X);
  DIFDIFX=dif(dif(X));
  DIF2X=dif2(X);
  LAGX=lag(X);
  LAGLAGX=lag(lag(X));
  LAG2X=lag2(X);
  DIFLAG=dif(lag(X));
  LAGDIF=lag(dif(X));
run;






となるわけです。