data Q1;
X=1;Y='A';output;
X=2;Y='B';output;
X=1;Y='A';output;
X=3;Y='B';output;
X=4;Y='C';output;
X=4;Y='C';output;
X=1;Y='C';output;
X=2;Y='A';output;
X=3;Y='C';output;
X=3;Y='A';output;
run;
そこから、Xについてのカウント集計のデータセット
Yについてのカウント集計データセット
XとYの組み合わせについての集計
の3つを1ステップで作りたいとします。
え?そんなん、あのプロシジャで簡単に・・と思った人は、ちょっと黙っててください。
今回はハッシュ(反復子)オブジェクトでカウント集計をする方法を紹介します。
先にコードから
data DS_X(keep=X count)
     DS_Y(keep=Y count)
     DS_XY(keep=X Y count)
;
informat X Y COUNT;
  if _n_ = 1 then do;
   declare hash hx(suminc: "count", ordered: "yes");
   declare hiter ix("hx");
   hx.defineKey('X');
   hx.definedone();
   count = 1;
   declare hash hy(suminc: "count", ordered: "yes");
   declare hiter iy("hy");
   hy.defineKey('Y');
   hy.definedone();
   count=1;
   declare hash hxy(suminc: "count", ordered: "yes");
   declare hiter ixy("hxy");
   hxy.defineKey('X','Y');
   hxy.definedone();
   count=1;
  end;
 do while (^FL);
   set Q1 end=FL;
   rc=hx.ref();
   rc=hy.ref();
   rc=hxy.ref();
 end;
 rc=ix.first();
 do while(rc=0);
   rc=hx.sum(sum:count);
   output DS_X;
   rc=ix.next();
 end;
 rc = iy.first();
 do while(rc=0);
   rc=hy.sum(sum:count);
   output DS_Y;
   rc=iy.next();
 end;
 rc = ixy.first();
 do while(rc=0);
   rc=hxy.sum(sum:count);
   output DS_XY;
   rc=ixy.next();
 end;
 stop;
run;
長すぎ・・・・。
ただ、中身は部分、部分の繰り返しで、構造自体は非常に簡単です。
declare hash hx(suminc: "count", ordered: "yes");のsuminc:、
これは、ハッシュオブジェクトのキーが、何かしらのメソッドにおいて、参照されると
指定した変数の値が、キーごとに+1加算されていくものです。
それで
 do while (^FL);
   set Q1 end=FL;
   rc=hx.ref();
   rc=hy.ref();
   rc=hxy.ref();
 end;
の部分はrefメソッドで、キーがハッシュオブジェクトにすでに存在するかをチェックするcheckメソッドの機能に加えて、存在しない場合はそのままaddメソッドでハッシュにデータを追加するという多段階機能をもった便利メソッド。
もう読めたと思いますが、このrefメソッドによって、値の初回出現時にハッシュオブジェクトに追加されたデータが、続いて同じ値が出現した時にsumincの働きによって、カウンタが+1されていくという性質を使って、集計しているんですね。
そして最終的にsumメソッドで値を格納します。
そして最終的にsumメソッドで値を格納します。
集計条件分、ハッシュオブジェクトをつくり、ハッシュ反復子オブジェクトの全データをループで書きだすことにより、まるで1ステップ内で複数回のデータステップの処理を行っているような形にしているわけです。
さて、もうお気づきだと思いますが、今回の処理は普通にfreqプロシジャを使えば
proc freq data=Q1 noprint;
 table X/out=DS_X(drop=percent);
 table Y/out=DS_Y(drop=percent);
 table X*Y/out=DS_XY(drop=percent);
run;
1ステップで終わるうえにたった5行です。
今回のケースに限っていえば、わざわざハッシュでやってたら、ちょっと、ご苦労様!って感じです。
実は、次の記事でこの仕組の応用例をやりたかったので、基礎の紹介としてやりたかっただけです。
ただ、こういった単純集計においても、場合によってはメリットが無いわけではないです。
例えば、infileなどでcsv等のデータを読み込んで、集計をする場合、freq等で集計するためには
まず、データセットを作成してから、そのデータセットに対してプロシジャ処理をかけなければならないので、どうあがいても2ステップかかります。
ところが今回の方法だと、1つのデータステップで、データの読み込みからダイレクトに集計結果のデータセットがつくれます。単純に読み込んだだけのデータセットが必要ない場合においては、有効です。
またfreqなどプロシジャは、複数の変数で集計はできますが、あくまで1回の実行につき、1つのデータセットが対象です。data=で複数のデータセット指定はできません。
ところが、ハッシュオブジェクトの場合は、ハッシュオブジェクトに突っ込んでから処理するので、流し込むデータセットが複数であっても1ステップでかけます。
またデータステップなので、途中で値の合成や、何かしらの処理を行って集計できます。
繰り返しの部分をうまくマクロにしたりすれば、すっきりかけます。
0 件のコメント:
コメントを投稿