ラベル nway の投稿を表示しています。 すべての投稿を表示
ラベル nway の投稿を表示しています。 すべての投稿を表示

means(summary)プロシジャのclassステートメントに関連してtypes ways nwayの話

たまに質問されるのが、meansやsummaryプロシジャで

ERROR: 適切な処理量を超えるクラス変数の組み合せの種類が
       要求されました。 TYPES または WAYS ステートメント、
       あるいは NWAY オプションを使用して、
       組み合せの種類の生成を制限してください。

ってメッセージがでるんですが、どうしたらいいですか?って感じの質問です。
どうもclassステートメントととbyステートメントの違いがあんまりピンときていない感じで、
とりあえず層別化する変数を全部つっこんだらこうなったって感じが多いです。

実際、classステートメント、ちょっとわかりにくですよね。僕も難儀しました。

記事:MEANSプロシジャのnwayオプションとTYPESステートメントの話
http://sas-tumesas.blogspot.jp/2013/10/meansnawytypes.html

でnwayとtypesについては触れていたのですが、waysについては忘れていたので整理ついでにもう一度やりましょう。


data Q1;
call streaminit(777);
do i = 1 to 20;
 C1=rand('table',1/2);
 C2=rand('table',1/2);
 C3=rand('table',1/2);
 C4=rand('table',1/2);
 X =int(rand('uniform')*10);
 output;
end;
drop i;
run;























データはなんでもいいです。
今回はC1-C4という4つの層別化変数と、集計対象のXというデータセットです。

留意してほしいのが、層別化変数に全て値が入っている、欠損がないという点です。
何故かというとclass変数に欠損が入っていた場合について、これまた何回も質問される間違いがあるんですが、それについては次回説明します。

byでやるなら、

proc sort data=Q1;
 by C1 C2 C3 C4;
run;

として

proc summary data = Q1;
by C1 C2 C3 C4;
var X;
output out=A0 mean= / autoname;
run;

とすれば















ってな感じで、C1からC4について、元のデータに存在している全パターンで集計結果がでています。

一方 classで同じようにC1からC4を指定してまわすと

proc summary data = Q1;
class C1 C2 C3 C4;
var X;
output out=A1 mean= / autoname;
run;

結果は以下










































































はい、全部で74オブザベーションでてます。
ここで、はぁ?なんで?と思われた方はmeans summaryプロシジャでのclassステートメントの
理解ができていないということになります。

どうしてかというと

全体集計(絞りなし)-0クラスレベル
C1の値で絞って集計した結果、C2で絞って集計した結果、C3の値で絞って集計した結果、C4の値で絞って集計した結果 -1クラスレベル
そして、C1とC2の出現している値の全組み合わせで、絞った結果、C1とC3、C1とC4・・・といった2クラスレベルといったように出現しているクラスの全組み合わせで、全レベル分でるわけです。
なので、値のパターンがそれなりにある変数をいくつもclassにしているすると、集計する組み合わせパターンはあっという間に爆発的な数になって、冒頭のようにSASがギブアップメッセージをだすわけです。

そこで、まずはnway

proc summary data = Q1 nway;
class C1 C2 C3 C4;
var X;
output out=A2 mean= / autoname;
run;













class変数の全てを使ったフルクラスレベルの結果のみを使用します。

次にtypesを使うと欲しい組み合わせのみを取得できます。
例えばC1とC2の2クラスレベルでの層別結果だけが欲しいのであれば
(その場合、C3 C4をclassステートメントに指定する意味がなくなりますが…)

proc summary data = Q1;
class C1 C2 C3 C4;
types C1*C2;
var X;
output out=A3 mean= / autoname;
run;







って感じです。


或いは、C1とC2 C3 C4それぞれを組み合わせた2クラスレベルが欲しければ
proc summary data = Q1;
class C1 C2 C3 C4;
types C1*(C2 C3 C4);
var X;
output out=A4 mean= / autoname;
run;













といった感じです。


続いて、waysの場合は、欲しいクラスレベルのレベルを数字で指定します。
0クラスレベル(つまり全体集計)と、1つのクラス変数のみをそれぞれ使った1クラスレベルの結果が欲しければ

proc summary data = Q1;
class C1 C2 C3 C4;
ways 0 1;
var X;
output out=A5 mean= / autoname;
run;











となります。

あまり、いい説明ではありませんでしたが、これが冒頭のTYPES WAYS NMAYいずれかを使って結果を絞ってくれというSASのお願いに繋がるのでした。

以上

MEANSプロシジャのnwayオプションとTYPESステートメントの話

たとえば以下のように、投与群(A群、B)、性別(男性、女性)、年齢カテゴリ(高齢者、非高齢者)という3水準と体重をもった100オブザベーションのデータセットがあるとします。(体重の作り方は超適当なので気にしないでください)


data TEST;
call streaminit(1234);
 do SUBJID=100 to 199;
  if rand('uniform')<0.5 then ARM='A群';else ARM='B群';
  if rand('uniform')<0.3 then SEX='男性';else SEX='女性';
  if rand('uniform')<0.7 then AGE='非高齢者';else AGE='高齢者';
  if SEX='男性' then WEIGHT=round(rand('normal')*15+65,0.1);
  if SEX='女性' then WEIGHT=round(rand('normal')*15+45,0.1);
  output;
 end;
run;




これに対して、以下のようにMEANSあるいはSUMMARYのclassに3水準を指定して
平均値を求めるようにしてデータセット作成を実行するとどうなるでしょうか?

proc means data=TEST noprint;
 class ARM SEX AGE;
 var WEIGHT;
 output out=OUT_1 mean=MEAN;
run;





























上記のように27オブザベーションで統計量が算出されます。

0水準の場合(全体)=1
1水準の場合を3変数に対して=2×3=6
2水準の場合を3変数から2変数を選ぶ組み合わせ全てに対して=3C2×4=12
3水準の場合 2×2×2=8

なので1+6+12+8=27となるわけです。

全部の組み合わせについて計算してくれるのは凄いのですが、これらの結果全てを使用したくて
プロシジャを実行することは少なく、だいたいは欲しい部分は決まっていると思います。

今欲しいのが一番高い水準→3水準であった場合nwayオプションを指定すると
_TYPE_の値が一番高い部分のみ抽出してくれます。

proc means data=TEST nway noprint;
 class ARM SEX AGE;
 var WEIGHT;
 output out=OUT_2 mean=MEAN;
run;



また、例えば群×性別×年齢と群×年齢の組み合わせの結果が欲しいといった場合は
TYPESステートメントで欲しい水準の組み合わせを指定します。

proc means data=TEST noprint ;
 class ARM SEX AGE;
 types ARM*SEX*AGE ARM*AGE;
 var WEIGHT;
 output out=OUT_3 mean=MEAN;
run;

すると


でめでたしめでたし





MEANSプロシジャのOUT=で作成されるデータセットの要約統計量が入る変数名について

例えば以下のような適当なデータがあったとします。

data Q_1;
call streaminit(1011);
 do i=1 to 100;
  A=ceil(rand('uniform')*10);
  B=ceil(rand('uniform')*2);
  C=ceil(rand('uniform')*5);
  D=ceil(rand('normal')*10);
 output;
 end;
drop i;
run;



例えばAでグループ化して平均B,C,Dそれぞれの変数について平均をとりたければ

proc means data=Q_1 noprint nway;
 class A;
 output out=OUT_1 mean= X Y Z;
run;

でいいわけです。



この時、作成されたデータセットOUT_1について
Bの平均は変数X Cの変数はY DはZに格納されます。
変数の位置関係が重要になるので注意してください。


さてここで

proc means data=Q_1 noprint nway;
 class A;
 output out=OUT_2 mean=;
run;

のようにmean=で何も指定しないとどうなりますか?
エラーにならず


Bの平均はB Cの平均はC Dの平均はDです。
出したい要約統計量が一つであれば、こっちの書き方の方がわかりやすいかもしれませんね。

ちなみにもし、出したいのがBとDの平均とCの合計が欲しいといった
わがままも下のように( )で指定して実現可能です。

proc means data=Q_1 noprint nway;
 class A;
 output out=OUT_3 mean(B D)=BMEAN DMEAN SUM(C)=CSUM;
run;












創意工夫は無限大、meansプロシジャは優秀ですね