【疑問】IF THEN 直後のサブセット化IFの挙動 どなたかお知恵を

最近あった、僕がうまく解釈できなかった事象について書きます。
どなたか、わかる方がいらっしゃればお力を貸してください。

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

data Q1;
X=1;Y=2;Z=3;output;
X=2;Y=3;Z=4;output;
X=1;Y=1;Z=3;output;
run;








それに対してSASを勉強中のYさんが
「X=1であるデータのうち、Y=2のデータのみを抽出したくて、こう書いたのですが
うまくいきませんでした。何が間違ってますか?」
と言ってきて、コードを見てみると

data E1;
 set Q1;
 if X=1 then if Y=2;
run;

でした。

僕はいいました
「なんだこの変な書き方。その条件なら、日本語の文章に惑わされず
 andで結ぶだけじゃない?」

data A1;
 set Q1;
 if X=1 and Y=2;
run;






まあ、Yさん的には目的の処理が書けてこれでOKなのですが、
問題は

data E1;
 set Q1;
 if X=1 then if Y=2;
run;

がエラーもワーニングなく実行できるということです。
僕はてっきりエラーになると思っていました。
エラーにならないのなら、andで結んだのとおんなじ結果かな?と思いました。
if X=1 の場合にサブセット化IFでY=2がかかるのかと、、。
ところが結果は以下のようになりました。






なにこれ?どういう処理がされたらこんな結果になんの??
X=1で絞れているわけではないし、Y=2でも絞れてないし、なんで2obs?
しかも2レコード目はなんで出てきた??

しばらく考えたのですがわかりませんでした。

ちなみにどうしてもandを使わず、if 今回の処理をするならどう書くかを考えると

data A2;
 set Q1;
 if X=1 then if Y=2 then output;
run;

が思い浮かんだので実行すると、これは正しい結果を導きました。





じゃあ、以下のコードも通るよねと考えました

data E2;
 set Q1;
 if X=1 then if Y^=2 then delete;
run;

しかし、また変な結果です。






なんで??
絶対、if X=1 then if Y=2;なんて第一感悪手で実戦では本能的に書かないからいいんですけど
、どうしてもひっかかる、気になります!気になるんです

if then ステートメントの後に、if 条件式だけを書いたり、
if then deleteを書くと、変な結果になるのはなぜなんでしょうか??

どなたか、推論でもいいので教えてください。

=======================
追記
=======================
解決しました!的確で素晴らしいコメントをいただきました!
詳細はコメント欄をみてください。
また一つ賢くなれた気がします。

ちなみにコメントくださったのはブログ「SAS忘備録(URL http://sas-boubi.blogspot.jp/)」
の作者様です。
SAS忘備録は、本当に素晴らしくて、僕のと違って文章が読みやすいし押しつけがましくないし
丁寧ですし、書かれていることも洗練された役にたつ知識ばかりで、見習いたいです。



4 件のコメント:

  1. こんにちは。
    もう解決されてるかもしれませんが。。
    これ面白いですね。この発想は無かったです。

    これは推測ですが、内部で以下のようになってるんだと思います。
    「then do」は分かりやすくするために勝手に追加しちゃってます。

    data E1;
    set Q1;
    if X=1 then do;
    if Y=2;
    end;
    output;
    run;

    いやー、面白い!

    返信削除
  2. ありがとうございます!!
    あ~、そういうことか、3レコード目がでないのはX=1なのにY=2でないからで、2レコード目がでちゃうのは暗黙のOUTPUTが効いているからってことですか。

    面白いですね

    返信削除
  3. ちなみに、これ実戦でも使えますね。
    「ある特定の条件のみ、抽出条件を設定し、
    それ以外は全て出力」
    という事をしたい時に、大分スマートな書き方になりますね。
    今回の例だと「X=1」の場合のみ抽出条件を設定していて、
    IFIF条件以外で書こうとすると以下のように微妙に文が長くなりますし。

    data E1;
    set Q1;
    if (X=1 and Y=2) or X^=1;
    * if X=1 then if Y=2;
    run;

    返信削除
  4. 確かに、原理をわかっていれば、筋が通っていて実戦手順として充分ありですね。
    クールですね。
    ただ、一見でぱっと理解できる人がそんなに多くなさそうなので、他の人がみる場合は
    data E1;
    set Q1;
    if X=1 then if Y=2;
    output;
    run;

    outputぐらい入れといた方がいいかもしれないですね。
    僕なんか、考えても何が起こっているかわかんなかったわけですし、、

    返信削除