2015年6月22日月曜日

RETAINステートメント徹底入門





RETAINは、前のオブザベーションの値を保持してくれるステートメントです。



構文

RETAIN  値の保持機能を持たせる変数   初期値 ;

  • 値の保持機能を持たせる変数」… データセット内に存在する変数を指定しても、うまくREATINされません。新しい変数を作って、それを指定しましょう。
    • 値の保持機能を持たせたいのが文字変数の場合は、先にLENGTHステートメント等で長さの設定も忘れずに。
  • 初期値」… 省略化



とりあえず、具体例を見ていきましょう。



サンプルデータ

data DT1;
input A @@;
cards;
1 . 5 . . 10
;
 A  
    1 
    .  
    5  
    .  
    .  
  10  



例①

data OUT1;
   set DT1;
   retain B 0;
run;

  B   
   1 
   0  
   .  
   0  
   5  
   0  
   .  
   0  
   .  
   0  
 10  
   0  


変数Bに初期値「0」を与えて、最後のオブザベーションまでその値が保持され続けていることが確認できます。



例②

data OUT2;
   set DT1;
   retain A2;
   if A^=. then A2=A;
run;

  A2   
   1 
    1  
   .  
    1  
   5  
    5  
   .  
    5 
   .  
    5  
 10  
  10  


  • RETAINで変数A2に値保持機能を持たせます。
  • IF文で、変数Aに何か値があれば、その値をA2に放り込んでいます。


結果として、「変数Aに値がなければ、前のオブザベーションから値を引き継ぐ」という処理をした変数A2を作ることが出来ます。




実践例①


サンプルデータ
data DT2;
input NO$ DAY POINT$;
cards;
001 1 100pt
001 2 .
001 3 .
001 4 150pt
002 1 .
002 2 200pt
002 3 .
002 4 .
;
 NO  
 DAY 
 POINT 
  001
  1  
 100pt 
  001
  2  
  
  001
  3  
   
  001
  4  
 150pt
  002
  1  
  002
  2  
 200pt   
  002
  3  
   
  002
  4  
    

NO      ・・・ 顧客NO
DAY    ・・・ 来店日
POINT ・・・ ポイント


サンプルデータの説明。
とあるお店がポイントカードを導入したとします。
顧客NO毎にポイントを管理していて、来店してない日はポイントをNULLにしています。

(突っ込みどころ満載のデータですが、あくまで説明用のためのデータです。。)


ここで、来店してない日は、前回来店時のポイントで埋めたいとします。

 NO  
 DAY 
 POINT2 
  001
  1  
 100pt 
  001
  2  
 100pt
  001
  3  
 100pt
  001
  4  
 150pt
  002
  1  
  
  002
  2  
 200pt   
  002
  3  
 200pt 
  002
  4  
 200pt


*** 来店してない日を、前回来店時のポイントで埋める。 ;
proc sort data=DT2;
   by NO DAY;
run;

data OUT3;
   set  DT2;
   by  NO ;

   length  POINT2 $8.;
   retain  POINT2;
   if  first.NO then POINT2="";
   if  POINT ^="" then POINT2 = POINT;
run;

以下記事の方法も組み合わせてます。
「FIRST.BY変数」と「LAST.BY変数」で、グループ毎の最初と最後のオブザベーションを特定する。


  • まず「retain  POINT2」で、POINT2に値保持機能を持たせる。(この変数にポイント埋めをします)
  • if  first.NO then POINT2=""」で、RETAIN機能を有したPOINT2を、顧客NOごとに初期化(欠損値に)する。(初期化しないと、前の顧客のポイントがRETAINされちゃうので。)
  • if  POINT ^="" then POINT2 = POINT」で、POINTに何か値があれば、その値をRETAIN機能を有したPOINT2に放り込んでいます。

これで、ポイントを埋めた変数POINT2の完成です。



実践例②


サンプルデータ
data DT3;
input SUBJID$ VISITNUM VAL;
cards;
001 0 100
001 1 200
001 2 .
001 3 .
002 0 300
002 1 .
002 2 400
002 3 .
;
 SUBJID 
 VISITNUM 
 VAL 
  001
  0  
 100
  001
  1  
 200
  001
  2  
  . 
  001
  3  
  .
  002
  0  
 300
  002
  1  
  .   
  002
  2  
 400 
  002
  3 
  .

SUBJID          ・・・ 患者ID
VISITNUM    ・・・ 測定時期  0=投与前、1=投与1日後、2=投与2日後・・・
VAL                ・・・ なんかの測定値


サンプルは、治験薬投与前後にとある検査値を測定したデータだとします。

やりたい事は、測定値が欠損値であれば、以下のように前回測定された値を引っ張ってきたい。
(ただし、前回測定したのが投与前の場合は、投与後の値としては引っ張ってきたくない。)

 SUBJID 
 VISITNUM 
 VAL2 
  001
  0  
 100
  001
  1  
 200
  001
  2  
 200  
  001
  3  
 200
  002
  0  
 300
  002
  1  
  .   
  002
  2  
 400
  002
  3 
 400


* 前回測定値を引っ張ってくる(投与前以外) ;
proc sort data=DT3;
   by SUBJID VISITNUM ;
run;

data OUT4;
   set DT3;
   by SUBJID;

   length VAL2 8.;
   retain VAL2;

   if first.SUBJID then VAL2=.;
   if VAL^=. then VAL2=VAL;

   output;
   if VISITNUM=0 then VAL2=.;
run;


やってる事は、ほぼ「実践例①」と同じ。

ただし投与前の測定値は、投与後にRETAINしたくないので、
特定条件の時だけ、RETAIN機能を無効にする
の方法を組み合わせてます。(プログラム青字部分)


📝注意
記事の中で使用している「FIRST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かなくなる事があります。



0 件のコメント:

コメントを投稿