2014年5月28日水曜日

色々な例数を簡単に出す2



色々な例数を簡単に出す」のデータステップ編です。



サンプルデータ
data DT1;
  label  FOOD     = "購入食品"
          PRICE    = "価格"
          EATFLG = "食べたフラグ"
  ;
  length FOOD $20.;
input  FOOD$  PRICE  EATFLG;
cards;
ジュース  150  1
カップ麺  100  .
ジュース  100  1
ジュース  200  .
カップ麺  200  .
;



求めたい結果
 購入数  ジュース購入数  カップ麺購入数  
  5  3    2



データステップで各例数を計算
data DT2;
   set DT1 end=EOF;           /* ① */

   C1 + (FOOD^="") ;          /* ② */
   C2 + (FOOD="ジュース") ;
   C3 + (FOOD="カップ麺") ;

   if  EOF;                         /* ③ */
   keep C:;
run;



解説
前に紹介した「SUMステートメント入門」と「1行プログラミング6:TRUE/FALSEを計算に利用する。」の合わせ技です。

  • ① まず「end = 一時変数名」と書くと、最終行の一時変数に1が入ります。
  • ② 条件式によって返される「1.true」「0.false」をSUMステートメントで合計していきます。
  • ③ 最終的な合計がでる最終行のみを残します。






応用
グループ毎に色々な例数や合計を出すこともできる。

たとえば、サンプルデータで以下のように「食品毎の例数や合計」を出したいとする。
 食品  購入数  合計金額   食べた食品の合計金額 
 カップ麺 2   300 0
 ジュース 3   450 250


データステップでグループ毎の例数や合計を出す。
proc sort data=DT1; by FOOD; run;

data DT3;
   set DT1;
   by FOOD;
   if first.FOOD then call missing(C1,C2,C3);   /* ① */

   C1 + (FOOD^="");                                 /* ② */
   C2 + PRICE;
   C3 + (EATFLG=1)*PRICE;

   if last.FOOD;                                        /* ③ */
   keep FOOD C:;
run;



解説
  • ① グループの各先頭行の時、計算結果を入れる変数を初期化する(call missingでNULLにする)
  • ② SUMステートメントで合計していきます。
  • ③ グループ毎の最終行のみを残します。


「C3 + (EATFLG=1)*PRICE;」のところの仕組みを補足しておくと、 (EATFLG=1) の条件が
  • 「0.false」なら、C3 + 0*PRICEとなり、
  • 「1.true」なら、C3 + 1*PRICEとなり、
「true/false」によって合計に含めるかどうかのトリガーにしています。



📝注意点

今回のテクニックの中で使用している「END=オプション」「FIRST.BY変数」「LAST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かなくなる事があります。



6 件のコメント:

  1. 「SUMステートメントで合計していきます」ってありますけど、そんな処理してる部分が見当たりませんけど

    返信削除
  2. コメントありがとうございます。
    プログラム中で青文字で示しているところが、SUMステートメントを利用している部分になります。

    返信削除
  3. はじめまして。データステップでsetだけしているのですが、なぜかソースデータでNullの変数に前行の値が入ってきます。。
    文字変数に||を使用して「日付(投与日数)」を代入しているだけなのです。。
    retainはしていません。。原因を探しているのですが、見つからずコメントで質問させていただきました。なにかヒントをいただけると幸いです。
    ---
    data a;
    set x y; /*xは列名取得用の行なしデータ*/
    col1= stdtc||"("||compress(days,best.)||")";
    run;

    返信削除
  4. 原因はよくわからないままですが、ラベル用の0行データセットをsetするのをやめてみたら、Missingの行が復活しました。お騒がせいたしました。

    返信削除
    返信
    1. tikiさん、コメントありがとうございます。
      解決されたとのことですが、一応retainのような挙動をしてしまった原因について解説した記事のリンクを貼っておきますね。
      https://sas-boubi.blogspot.com/2014/08/set_5.html

      ちょっと解説が分かりづらいかもなので、不明点などがありましたらまたコメント頂ければと思います。

      削除
    2. お忙しい中ご返信+解説記事へのリンクをいただきありがとうございます!とってもうれしいです。
      余裕がないので今まだ拝読できていませんが、来週には落ち着くはずなのでリンク先拝読させていただきます。
      ありがとうございました。

      削除