詰めSAS8回目_循環するLAG処理(1つ前のOBSの値を取得するとともに最初のOBSについては最終OBSの値を持つようにする)

例えば

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


のようなデータセットがあったとして、そこから、
ひとつ前のオブザベーションの値を変数「LX」にいれる、ただし先頭については
ひとつ前のオブザベーションが存在しないので、循環して最後の値をとってくるという
問題があったとします。

目的とするデータセットは以下の形です。
↓【目的局面図】















さて、どう解くのが最短でしょうか?
ちなみに1手詰めです(1ステップで処理できる)

まず、LAG関数が第一感で思い浮かぶ方が多いかと思います。
data A;
 set Q1;
  LX=lag(x);
run;

しかし、これだと循環が表現できません。


当然こうなります。
LAG関数の使用は、今回はドツボ行きです


【解法】
data A1;
 set Q1 Q1 nobs=tobs;
  LX=X;
  if _N_<tobs/2 then delete;
 set Q1;
run;

nobs=やend=はsetで複数のデータセットを指定した際にまとめての値しかだせません。
なので上記でのnobsの中身は20です。
そこでサブセット化IFで1-9番目のオブザベーションをdeleteしているので
この時点で残っているのは10,11,12,13,14,15,16,17,18,19,20の11オブザベーション
つまり、ケツの1オブザベーションを頭に乗っけた形で11obsのデータセットが一時的に
できているわけです。
そこで、さらにSetを打つわけです。
おさらいですが、Set;Set;は一度でもファイル終端をどこかのデータセットで見つけたら
処理が打ち切られるので、結果として指定されたデータセット中、最小のオブザベーション数で
まとめられるという性質を持っています。
11obsと10obsをSet Setしているわけなので、作成されるデータセットは10obsです。

説明が下手なので、もしピンと来なければ実際に動かしてみてください。







4 件のコメント:

  1. こんにちは。
    いつも参考にさせて頂いてます。

    説明されてる方法はパズル的な解き方で面白いですね!
    おもわず「あ~なるほど~」と言ってしまいました笑

    わたしはなんの捻りもないSETステートメントのPOINTを使ったやり方を思いつきましたが、色々な解き方を考えるのも結構楽しいですね!
    ↓ちなみにわたしが考えた方法です。

    data A1;
    set Q1 NOBS=TOBS;

    PNT=_N_-1;
    if PNT<1 then PNT=TOBS+PNT;

    set Q1(rename=(X=LX)) point=PNT;
    run;

    返信削除
    返信
    1. ありがとうございます!!
      見てくれて本当にありがとうございます。

      いっつも、間違ったコードを垂れ流していてすみません。

      あ~、やられました。
      ご指摘いただいたコードの方が無駄がない。スマートですね。
      こっちを最適解にしましょう。

      でも、
      PNT=TOBS+PNTの部分の+PNTは要らないんじゃないですかね??
      _N_=1の時だけケツ(point=TOBS)からとるようにしているんで、+PNTのところは条件式を通る時は必ず0じゃないです??

      意図を読み切れていなかったら赤っ恥ですが、、、



      削除
  2. たしかに今回の目的局面だと「+PNT」は要らないです。

    入れている理由として
    たとえば目的局面が「3個とか4個とかずらしたい」っていう場合に、
    「PNT=_N_-1;」の部分を
    「PNT=_N_-3;」とか変えれば3個ずれてくれるので、応用が利くかなぁと思って「+PNT」を入れてみました。

    返信削除
    返信
    1. あぁ、そうか!そうですよね!しまった!
      重ね重ね有難うございます!!

      今後もぜひ、よろしくお願いします

      削除