タイトルで意味がわかりますでしょうか?うまく説明できません
ベン図で書くと、上の黄色の部分です(ペイントで適当に書いたベン図なので、○の大きさが違う、、)
例えば
data Q1;
do X=1,3,4,6;
output;
end;
run;
data Q2;
do X=1,3,5,6,8;
output;
end;
run;
のようなデータセットがあった場合に1つのデータセットにしかないXの値をもった結果
を得るには、どんなコードを書けばいいでしょうか?
ただし、MergeステートメントとSQL両方のやり方で詰ませないといけないというのが
今回の問題です。
え?第一感楽勝!と思われるかもしれませんが、案外、つまづきませんか?
実際、このタイプの結合処理って、頻度少ない気がします。
大体は両方一致するものを残すか、片方を全部残して結びつくものを残す、いわゆる内部結合や片側外部結合が大半ですよね。
実は今回も自分の解答に自信がなくて、もし間違いや、抜け穴、最適じゃない書き方であれば
ご指摘いただけると助かります。
以下、(一応)解答
【MERGEの場合】
data A1;
merge Q1(in=ina)
Q2(in=inb);
by X;
if ^(ina*inb);
run;
こんな感じでしょうか?
ifのところは (ina=1 and inb=0) or (ina=0 and inb=1)みたいな感じでもいいですし
^(ina and inb)でも、ようはin=で指定した変数が全部1になるケースを除く書き方をしていれば
なんでもいいです。
【SQLの場合】
proc sql noprint;
create table A2 as
select coalesce(Q1.X,Q2.X) as X
from Q1 full outer join Q2
on Q1.X=Q2.X
where ^Q1.X | ^Q2.X;
quit;
こんな感じでしょうか?
完全外部結合がみそですね。
わかりやすくするために、create tableとりはずして
where句で Q1.X=0 or Q2.X=0 をしている部分も外しましょう(|はorを意味する記号)
proc sql;
select Q1.X label='Q1のX'
,Q2.X label='Q2のX'
from Q1 full outer join Q2
on Q1.X=Q2.X;
/* where ^Q1.X | ^Q2.X;*/
quit;
こうしたら
こうなるので、これをみれば、上のコードも理解しやすいはずです。
どっちかが欠測の場合を抽出しているんで、最初に見つけた欠測以外の値を取得する
coalesceが効いいるわけですね。
あ、ちなみに、僕が最初に思いついたSQLは
proc sql noprint;
create table A3 as
select X from Q1
union all corr
select X from Q2
except
select coalesce(Q1.X,Q2.X) as X
from Q1 innner join Q2 on Q1.X=Q2.X;
;
quit;
です。まあ、確かにベン図を表現していなくはない、気持ちはわからなくはないと思っていただければ浮かばれます。
SQLで他のデータセットと共通、非共通のデータをとる(差集合 積集合) EXCEPT INTERSECT
SASは1obs読み込んで処理してアウトプットするのが基本で、よくも悪くもデータの格納されている順番(ソート)に縛られているところがあります。
対してSQLは集合論ベースの言語で原則的にデータの格納位置(アドレス)に縛られない書き方ができます。
今以下のような2つのデータセットがあるとします。
data Q_1;
input X $ Y $ Z $;
cards;
A C D
D B C
C A B
B B A
C A C
A C A
B A C
;
run;
data Q_2;
input X $ Y $ Z $;
cards;
D C D
D B C
C A B
B F A
C A C
C C A
F A C
;
run;
今Q_1について、Q_2に同じ内容のオブザベーションのあるレコードのみを抽出したいとします。
その場合、
proc sql;
create table A_1 as
select *
from Q_1
intersect corr all
select *
from Q_2
;
quit;
二つの抽出文をintersectで繋ぐことで共通のデータを残すことができます。
これをSASで書くなら
MergeのQ_2にin=をつけてQ_2からデータが読み込まれたらフラグがたつようにして
X Y Zを全部BYに指定して、in=が1になるデータだけを残す感じです。
この場合においては僕はSQLの方が、やりたいことの本質にあった、見通しのよい
コードになっていると思います。
また同様に、Q_1からQ_2と共通でない、かぶってないデータを欲しい場合は
proc sql;
create table A_2 as
select *
from Q_1
except corr all
select *
from Q_2
;
quit;
対してSQLは集合論ベースの言語で原則的にデータの格納位置(アドレス)に縛られない書き方ができます。
今以下のような2つのデータセットがあるとします。
data Q_1;
input X $ Y $ Z $;
cards;
A C D
D B C
C A B
B B A
C A C
A C A
B A C
;
run;
data Q_2;
input X $ Y $ Z $;
cards;
D C D
D B C
C A B
B F A
C A C
C C A
F A C
;
run;
今Q_1について、Q_2に同じ内容のオブザベーションのあるレコードのみを抽出したいとします。
その場合、
proc sql;
create table A_1 as
select *
from Q_1
intersect corr all
select *
from Q_2
;
quit;
二つの抽出文をintersectで繋ぐことで共通のデータを残すことができます。
これをSASで書くなら
MergeのQ_2にin=をつけてQ_2からデータが読み込まれたらフラグがたつようにして
X Y Zを全部BYに指定して、in=が1になるデータだけを残す感じです。
この場合においては僕はSQLの方が、やりたいことの本質にあった、見通しのよい
コードになっていると思います。
また同様に、Q_1からQ_2と共通でない、かぶってないデータを欲しい場合は
proc sql;
create table A_2 as
select *
from Q_1
except corr all
select *
from Q_2
;
quit;
のようにexceptで繋ぎます。
allは重複を勝手にけさない、corrは処理の時にきちんと変数名をみてやってください的な
役割です。
何かやりたいことがあるとき、データステップでやるかSQLでやるか迷った場合は
やりたいことをイメージ化してみるのがいいと思います。
思い浮かんだのがフロー図であれば、データステップ
ベン図ならSQLって感じで。
登録:
コメント (Atom)








