2014年8月13日水曜日

RETAIN vs SETステートメント



SETステートメントの落とし穴として紹介した「値の保持」「変数の初期化」の性質を利用したテクニックを紹介したいと思います。



サンプルデータ

data DT1;
   NO="001";  DAY=1;  POINT="100pt"; output;
   NO="001";  DAY=2;  POINT=""; output;
   NO="001";  DAY=3;  POINT=""; output;
   NO="001";  DAY=4;  POINT="150pt"; output;
   NO="002";  DAY=1;  POINT=""; output;
   NO="002";  DAY=2;  POINT="200pt"; output;
   NO="002";  DAY=3;  POINT=""; output;
   NO="002";  DAY=4;  POINT=""; output;
run;

proc sort data=DT1; by NO DAY; run;

 DT1
 NO  
 DAY 
 POINT 
  001
  1  
 100pt 
  001
  2  
 . 
  001
  3  
 .  
  001
  4  
 150pt
  002
  1  
 . 
  002
  2  
 200pt   
  002
  3  
 .   
  002
  4  
 .   


サンプルデータの説明です。
あるドーナツ屋さんがポイントカードを導入したとします。
顧客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

プログラム例

*** 1. RETAINを利用 ;
data DT2;
   length  POINT2 $8.;
   retain  POINT2;
   set  DT1;
   by  NO ;
   if  first.NO then POINT2="";
   if  POINT ^="" then POINT2 = POINT;
run;

*** 2. SETの性質を利用 ;
data DT3;
  set  DT1  DT1(obs=0 rename=(POINT=POINT2));
  by  NO ;
  if  POINT ^="" then POINT2 = POINT;
run;

RETAINについては、ここでは詳細を割愛します。
詳細解説は「RETAINステートメント徹底入門」をご覧ください。


そして、今回紹介したいSETの性質を利用した方法。
(まず一番先頭のリンクの内容を理解しておく必要があります。)

ポイントは上のプログラムで赤字にした箇所。
①「obs=0」は0行読み込むという意味、、つまり1行も読み込まない。
②「rename=」でPOINTをPOINT2にRENAMEしておく。

つまりここでやりたい事は、レコードは読み込まず、PDV上にPOINT2という変数の枠を作っておく事です。

③次に、上のプログラムの青字で示したDT1はPOINT2という変数を持っていません。
つまりこのデータセットからレコードを読み込むとき、PDV上のPOINT2は値の保持機能が働きます。



以下PDV処理の一部




















説明が難しいところなので、分かりづらいかもしれないけど、どうでしょうか。
他にも応用がきくので、いろいろ試してみると面白いです。


📝注意点

今回のテクニックの中で使用している「FIRST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かなくなる事があります。
(解説記事:「サブセット化IFでありがちな落とし穴」)



0 件のコメント:

コメントを投稿