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

詰めSAS6回目_由来するデータセットの情報で処理をする

以下の2つのデータセットを、変数名を共通のものにリネームしつつ縦結合し、なおかつ結合後のデータセットで、もともとどちらのデータセットにあったオブザベーションか判別できるように情報を付与せよといった問題になります。

data Q_1;
 A=1;B=2;output;
 A=3;B=4;output;
run;



data Q_2;
 C=5;D=6;output;
 C=7;D=8;output;
run;






上記の2つのデータセットから、下のデータセットを作ります。








なお、1ステップで行うのが最短で、新規データセットを作成する問題なので
appendプロシジャの採用は今回はおそらく悪手です。


【解法1】
data A_1;
 set Q_1(in=in1 rename=(A=X B=Y))
      Q_2(in=in2 rename=(C=X D=Y))
;
 if in1 then BASE='Q_1';
 if in2 then BASE='Q_2';
run;

inデータセットオプションはmergeステートメントと使って、外部結合(片方のオブザベーションを全て残す)ような処理の際によく使われますが、本来、そういった限定的な使用法ではなく、データセットの帰属にフラグをたてれる優秀なオプションなのでより柔軟に使用されるべきだと思います。


【解法2】
proc sql noprint;
 create table A_2 as
  select A as X,B as Y,'Q_1' as BASE
   from Q_1
    union all
  select C,D,'Q_2' as BASE
   from Q_2;
quit;

この方法で面白いのは、変数名をX,Yに変える処理をQ_1に対してしか行っていないのに後段の
Q_2の変数C、DもX,Yになって縦結合される点です。
これは unionにcorrをつけていないことに起因します。corrをつけると縦結合する際に変数名が同じ物同士をつないでくれますが、つけれなれば、どんな変数名であっても1つ目の変数は1つめの変数と結合されます。定義情報は一番最初のテーブルのものが強制されます。通常はそんなおっかない性質は扱いづらいので unionにはallとcorrをつけます。allを抜くと勝手に重複データを消してきます。
SASのSetステートメントの挙動と同じなのはunion corrで繋いだ場合ということになります。




=================================
おまけ in=は優秀
=================================
たとえば以下のようなデータセットがあったとします。

data GROUPDATA;
 input GROUP $10. SEX $;
 cards;
グループA 男性
グループA 男性
グループA 男性
グループA 女性
グループA 男性
グループA 女性
グループA 男性
グループA 男性
グループA 男性
グループA 女性
グループA 男性
グループB 男性
グループB 女性
グループB 女性
グループB 男性
グループB 女性
グループB 男性
グループB 女性
グループB 男性
グループB 女性
;
run;
























ここでAグループ、Bグループ、全体で見たときの男女の人数をカウントせよという問題があった
とします。










そういった時setステートメントで同じデータセットを縦につないで
一旦オブザベーション数が2倍になってデータが重複したデータセットをつくるコードを書きます。
ただし2つめのデータセットにデータセットオプションでin=を指定し、後にifでin=でたてた変数が
1の場合にグループ情報をダミー変数に置き換えます。
あとはグループ集計すればいいのです。
言葉で説明しにくいので実際にやってみてください、SASっぽいなぁと思わせる処理です。

data GROUPDATA_1;
 set GROUPDATA
      GROUPDATA(in=in1);
   if in1=1 then GROUP='全体';
 run;

proc freq data=GROUPDATA_1 noprint;
  tables GROUP*SEX/out=OUTPUT(drop=percent);
run;





詰めSAS5回目_データの重複を取り除く


データの重複を取り除く方法を考えます。
今回は全変数の値に対して重複をみて、ユニークな値のみ残すようにします。

data Q1;
input X Y Z $;
cards;
1 2 A
3 5 C
7 4 B
1 2 A
3 5 C
7 5 B
1 2 A
1 2 A
9 6 D
9 6 D
3 5 C
;
run;


のデータから




を作ります。


【解法1】
proc sort data=Q1 out=A1 noduprec;
 by X;
run;

byステートメントがないとsortプロシジャが動かせないので入れているだけで
指定はどの変数でもいいです。noduprecは全変数で同一の値を持つオブザベーションが
ある場合にまとめてくれます。

proc sort data=Q1 out=A1_ nodupkey;
 by X Y Z;
run;

のようにnodupkeyを使って全変数をbyステートメントに指定しても当然OKです。

【解法2】
proc freq data=Q1 noprint;
 tables X*Y*Z/out=A2(drop=COUNT PERCENT);
run;

freqプロシジャで組み合わせの頻度集計をしておいて、頻度と割合をdropすることで
必然的にユニークな値のみが残ります。

この方法のいいところは、今回は違いますが、たとえば、重複しているレコードの数が
2レコードの組み合わせのみ残せといったような、わけのわからない条件がついた場合に
頻度データを持っているので次のように対応できるというところです。

proc freq data=Q1 noprint;
 tables X*Y*Z/out=A2_(where=(COUNT=2));
run;

【解法3】
proc sql noprint;
 create table A3 as
  select distinct X,Y,Z
   from Q1
;
quit;

【解法4】
proc sql noprint;
 create table A4 as
  select X,Y,Z
   from Q1
  union
  select X,Y,Z
   from Q1
;
quit;

【解法5】
proc sql noprint;
 create table A5(drop=DUMMY) as
  select X,Y,Z,max(X) as DUMMY
   from Q1
   group by X,Y,Z
;
quit;

解法3-5はSQLです。書き方はほかにもいくらでもあるので、省略します。
普通に解法3で充分なのですが、個人的に面白いのは、冗長な処理ですが解法4です。
unionに allを指定しないと、結合後のデータから重複が取り除かれるという性質を利用して
自分に自分をくっつけて、同じものを消します。ぷよぷよみたいですね。