2017年12月12日火曜日

HASHオブジェクトで、Key変数毎に最小値・最大値・合計値などを取得する方法


(コピペ利用するための、ほとんど個人的なメモ)





* Sample Data ;
data DT1;
input NO:$3. SEX:$1. AGE:8.;
cards;
001 F 39
002 M 25
;
 NO・・・顧客ID
 SEX・・・性別
 AGE・・・年齢


data DT2;
input NO:$3. FOOD:$10. PURDATE:yymmdd10.;
format PURDATE yymmdd10.;
cards;
001 ORANGE  2017/12/11
001 APPLE   2017/12/13
001 CHERRY  2017/12/10
002 ORANGE  2017/12/15
002 APPLE   2017/12/05
;
 NO・・・顧客ID
 FOOD・・・購入食品
 PURDATE・・・購入日




上のデータから、顧客ID毎に購入日の最小値を取得したいとします。

data OUT;

    set DT1;

    /* 購入データをHashオブジェクトに格納 */
    if _n_=1 then do;

        length PURDATE 8.;
        call missing( PURDATE );

        dcl hash purhash( dataset:"DT2", multidata:"y" );
        purhash.definekey("NO");
        purhash.definedata("PURDATE");
        purhash.definedone();

    end;


    /* Hashオブジェクト内をループして、顧客IDごとの購入日の最小値を取得 */
     rc = purhash.find();
     if rc = 0 then MINDATE = PURDATE;

     do while (rc = 0);
          rc = purhash.find_next();
          if rc = 0 then MINDATE = min( MINDATE, PURDATE );
     end;

     format MINDATE yymmdd10.;
     keep NO SEX AGE MINDATE;
run;




解説

まずHashの触りは以下記事を読むと理解しやすいです。

http://sas-boubi.blogspot.jp/2015/02/hash.html
(SAS忘備録:Hashオブジェクトを使おう)




かいつまんで解説

  dcl hash purhash( dataset:"DT2", multidata:"y" );
  purhash.definekey("NO");
  purhash.definedata("PURDATE");
  purhash.definedone();

まずはHashオブジェクトの定義から。
データセットDT2をHashオブジェクトに格納し、「multidata:'y'」で、Key値の重複を許しています。
変数NOをKey値、変数PURDATEをKey値に関連づける変数として定義しています。



  rc = purhash.find();
  if rc = 0 then MINDATE = PURDATE;

findメソッドでHashオブジェクト内をKey値で検索。
該当するKey値があったら、取得したPURDATEをMINDATEに格納。



  do while (rc = 0);
    rc = purhash.find_next();
    if rc = 0 then MINDATE = min( MINDATE, PURDATE );
  end;

find_nextメソッドで、Hashオブジェクト内の次のレコードを検索。
該当するKey値があったら、取得したPURDATEをMINDATEと比較し、最小日付をMINDATEに格納。

これをHashオブジェクト内に該当するレコードがなくなるまで、do whileでループしています。




一応今回やってることは、SQLやMEANSとかの方が楽に求められるけど、DATAステップ内で完結できるのが最大のメリットだと思います。


📝注意

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



0 件のコメント:

コメントを投稿