ラベル ステートメント: MERGE の投稿を表示しています。 すべての投稿を表示
ラベル ステートメント: MERGE の投稿を表示しています。 すべての投稿を表示

2016年9月21日水曜日

SETやMERGEをした時、オブザベーション毎に結合元のデータセットがどれなのか判別する方法 【IN=オプション】



SETやMERGEで使えるIN=オプションについて解説をしたいと思います。



構文

SET   データセット1  ( IN = 一時変数1 )
          データセット2  ( IN = 一時変数2 )

          ・・・
;


・ データセット1 から持ってきたオブザベーションの場合「1」、それ以外「0」が 一時変数1 に入る
・ データセット2 から持ってきたオブザベーションの場合「1」、それ以外「0」が 一時変数2 に入る

・ 一時変数名は適当な名前でOK。またこの一時変数は出力データセットには残らない。




例


サンプルデータ作成
data DT1;
   length A 8. B $10.;
   A=1; B="aa"; output;
   A=2; B="bb"; output;
run;
  A  
  B  
  1 aa
  2 bb

data DT2;
   length A 8. C $10.;
   A=2; C="cc"; output;

   A=3; C="dd"; output;
run;
  A  
  C  
  2 cc
  3 dd


例① SETステートメントでの例
data OUT1;
  set  DT1 (in=FLG1)   DT2 (in=FLG2) ;

  /* 別の変数に格納してデータセットに残す */
  X = FLG1;
  Y = FLG2;
run;
  A  
  B  
  C  
  X  
  Y  
  1 aa  1  0
  2 bb
  1  0
  2 cc  0  1
  3 dd  0  1



例② MERGEステートメントでの例
data OUT2;
  merge  DT1 (in=FLG1)   DT2 (in=FLG2) ;
  by A;

  /* 別の変数に格納してデータセットに残す */
  X = FLG1;
  Y = FLG2;
run;
  A  
  B  
  C  
  X  
  Y  
  1 aa  1  0
  2 bb cc  1  1
  3 dd  0  1




実践例

上の例②で、DT1とDT2の両方に存在するBY値のオブザベーションを特定したい場合、以下の条件を書けばいい事が分かりますね。

if FLG1=1 and FLG2=1 then COMMON_FLG=1;


また、DT1になくて、DT2にのみ存在するBY値のオブザベーションを特定したい場合、以下の条件を書けばいけますね。

if FLG1=0 and FLG2=1 then DT2ONLY_FLG=1;


2016年6月29日水曜日

BY値繰り返しのマージを活用する。


↓前回の続きです。
「MERGEステートメントにBY値を繰り返すデータセットが複数あります。」 とログに出たとき、どんなマージがされているのか。


今回は、BY値を繰り返すMERGEの活用例を紹介します。

例えば製薬業界だと、治験とかで症例の一覧を作成したりしますが、そういった時に使えます。


例

data DT1;
input NO$ SEX:$10. AGE ;
cards;
001 男 25
002 女 30
;

data DT2;
input NO$ KIO:$200. ;
cards;
001 aaa
001 bbb
001 ccc
002 ddd
002 eee
;

data DT3;
input NO$ GAP:$200. ;
cards;
001 AAA
001 BBB
002 CCC
002 DDD
;

DT1
NO
 SEX  
 AGE  
  001     男    25  
  002     女  30   

DT2
NO
 KIO  
  001     aaa   
  001     bbb
  001     ccc
  002     ddd
  002     eee

DT3
NO
 GAP  
  001     AAA   
  001     BBB
  002     CCC
  002     DDD


上記3つのデータセットをNOをキーにマージして、最終的に以下のような形でEXCELの一覧を作りたいとします。










普通にMERGEすると、、

data OUT1;
   merge DT1 DT2 DT3;
   by NO;
run;


望み通りの形になりません(上記の黄色部分を欠損値にしたい)

厄介なのが、DT2とDT3による多対多のマージにより、BY値の繰り返しが起きて、上記3オブザベーション目のGAPにも値が引き伸ばされてしまっている点。




そこで以下で紹介したテクニックで値が引き伸ばされないようにすると、、
「OUTPUT」と「CALL MISSING」のコンボ技

data OUT1;
   merge DT1 DT2 DT3;
   by NO;
   output;
   call missing(of _all_);
run;


大体、望み通りの形になります。

BY変数にしているNOも繰り返し表示されないように、以下青字のような文を追加すれば完成です。
data OUT1;
   length _NO $10.;

   merge DT1 DT2 DT3;
   by NO;

   if first.NO then _NO=NO;

   output;
   call missing(of _all_);
run;

あとはこれをEXCELにペタっと貼れば完成です。


📝注意

今回のテクニックで使用している「FIRST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かなくなりやすいです。


2016年6月27日月曜日

「MERGEステートメントにBY値を繰り返すデータセットが複数あります。」 とログに出たとき、どんなマージがされているのか。


n対nのマージをすると出るログメッセージ。
具体的にどういう動きをするのか見てみます。

*** サンプルデータ ;
data DT1;
input A$ B$ @@;
cards;
001 vv 001 ww 001 xx 002 yy 002 zz
;

data DT2;
input A$ C$ @@;
cards;
001 aa 001 bb 002 cc
;

data DT3;
input A$ D @@;
cards;
001 10 002 20
;

DT1
A
  B  
  001     vv   
  001     ww
  001     xx
  002     yy
  002     zz

DT2
A
  C  
  001     aa   
  001     bb
  002     cc

DT3
A
 D  
  001     10   
  002     20


上記3つのデータセットを変数AをキーにMERGEした結果を以下に示します
data OUT1;
   merge DT1 DT2 DT3;
   by A;
run;

ログには 「NOTE: MERGEステートメントにBY値を繰り返すデータセットが複数あります。」 と出ます。

このログメッセージと出力結果はどういうものなのかというと、、
内部処理(PDVとか)が分かると理解しやすいですが、その辺は抜きで簡単に解説。
(注意: 以下はあくまでイメージなので、厳密な動きを表しているわけではないです)











まずBY変数Aの値毎にMERGEされます。
たとえばA="001"の1行目同士でMERGE、2行目同士でMERGEがされていきます。
ここで、A="001"の2行目はDT1とDT2にはあるけど、DT3にはありません。











なので上記黄色部分のように前のレコードで処理された値が引き継がれます。
(RETAINみたいなイメージですね)












同じ要領で上記のような形が結合結果となります。



BY値を繰り返すマージって、意図的にやる事は少ないと思います。
なので人・組織によっては 「ログにこのメッセージが出てるぞ!確認しろ!」 と怒られます。

もし意図的にやるのであれば、問題ない旨のコメントをプログラム文中に残しておいた方が良いです。

/* BY値の繰り返しメッセージが出てるけど問題なし */  っていうコメントではなく、どういったデータを意図していて、何故問題がないのか詳細を書いた方が良さそうです。


。。。つづく

2014年6月27日金曜日

MERGEにBYがない場合にWARNINGを出す


MERGEにBYを入れ忘れてしまうことがたまにあるかと思います。
こういった場合にWARNINGを出す「MERGENOBYオプション」があります。

options  MERGENOBY = WARN ;

data A;
  A=1;
run;

data B;
  A=1;
run;

data C;
  merge A B;
run;


ログ
WARNING: BYステートメントがMERGEステートメントに指定されていません。




初期状態(WARNINGを出さない)に戻す場合は以下の通り。

options MERGENOBY = NOWARN ;



プログラム開発中だけでもこのオプションを入れておくほうがプログラミング時のミスを軽減できるかと思います。


2014年3月23日日曜日

MERGEステートメントの落とし穴




むかし、MERGEでやってしまったミスです。


サンプルデータ

data A;
input NO$ NO2 V1;
cards;
001 1 1
001 2 1
001 3 1
002 1 1
002 2 1
;

data B;
input NO$ V1 V2;
cards;
001 0 1
002 0 2
;

 AB
 



問題

サンプルデータより以下のプログラムを実行すると、①②どちらのデータが出来るでしょうか?

data C;
   merge A  B;
   by  NO;

   if  V2=1 then  V2=10;
   else  V2=20;
run;

 ①②

正解は②です。①だと思ったら要注意!


解説

はじめに、内部処理の説明は自分なりの解釈になってる可能性もあるので、あしからず。。


仕組み①
まずMERGEの仕組みを知る必要があります。
内部では、一旦プログラムデータベクトル(PDV)という入れ物に読み込んで加工してから、データセットに出力します。

以下は、サンプルデータの1行目をPDVに読み込むイメージ。




仕組み②
次が最大のポイントで、一対多のマージにおいて、
一側データセットBの変数は、BYグループ毎に1回しかPDVに読み込まれません。
(BYグループが変わるまで、PDVに残った値が保持される。。。RETAINのようなイメージ)

上記イメージの続きで、2行目をPDVに読み込むイメージ。




もし①のような結果が欲しい場合は、以下のように工夫する必要がある。
data C;
   merge  A(drop=V1)  B;
   by  NO;

   if   V2=1 then _V2=10;
   else  _V2=20;
run;




利用

この動きを面倒なものと思わず、逆に利用してやりましょう。
以下はマージの動きを利用してBYグループ毎に連番をふってます。
data B_;
  set B;
  SEQ=0;
run;

data D;
  merge A B_;
  by NO;
  SEQ+1;
run;




以上、説明がうまく出来た気がしないので、分かりにくい等のコメントを頂ければ、
さらに詳しく解説したいと思います。