means summaryプロシジャのclassステートメント指定変数の欠損値には気を付けてって話

年末、インフルにやられてダウンしてました。
締めの記事としてはたいしたことない内容ですが、means summaryのclass変数に欠損値があるのをうっかりすると、危険だという話です。

data Q1;
CL1=1;CL2=1;X=1;output;
CL1=1;CL2=1;X=1;output;
CL1=1;CL2=.;X=1;output;
CL1=2;CL2=2;X=1;output;
CL1=2;CL2=2;X=1;output;
CL1=2;CL2=.;X=1;output;
run;











というデータセットがあるとします。

まずCL1のみをclass変数に指定してみます。

proc summary data=Q1;
 types CL1;
 class CL1;
 var X;
 output out=A1 n=N;
run;






CL1が1,2の場合ともにN=3と正しい結果になっています。

続いて、CL2もclass変数に加えたうえで、
typesでCL1 CL2それぞれ単品でクラスした場合の結果のみだします

proc summary data=Q1;
 types CL1 CL2;
 class CL1 CL2;
 var X;
 output out=A2 n=N;
run;









はい、CL2の結果については1,2共にN=2で問題ないのですが
CL1の方について,あれ!!N=2で結果がさっきと違う!!
これなんですよね。複数のclass変数を指定して、あるクラスのみを見た時の結果と
そのclass変数単体で指定した場合の結果が異なるという現象です。

これは、classステートメントに複数変数を指定した場合、いずれか一つ以上の変数にnullが存在する場合、そのオブザベーションが全ての集計対象から外れるという仕様によるためです。

これは知らないと結構、恐ろしい仕様です。

nullが入っていても集計から外さないためにはnull自体を値とみなしてクラス変数として成立させる
という方法があります。
具体的にはclassステートメントにmissingオプションをつけるわけです。

proc summary data=Q1;
 types CL1 CL2;
 class CL1 CL2 / missing;
 var X;
 output out=A3 n=N;
run;

すると










こうなるわけです。1obs目がCL2の欠損値がひとつのクラスとして集計されている部分です。

しかし、これはこれで微妙に危険なところがあります。何故かというと、例えば
typesステートメントをつけずに全集計をデータセットに吐く場合

proc summary data=Q1;
 class CL1 CL2 / missing;
 var X;
 output out=A4 n=N;
run;



















こうなるわけですが、このデータセットの1obs目と2obs目について、CL1 CL2の値だけ
見ると両方null nullで見分けがつきませんよね。
_TYPE_の値が違うことから別層での集計であることがわかります。
1obs目はクラスなしの全集計、2obs目はCL2のnullクラスでの集計です。
例えばこのようなデータセットか、CL1 CL2の値で抽出して臨むべき集計結果を取得しようとする
場合、別層のものも同じ条件でかかってしまう恐れがあるわけです。

結局のところ、クラス変数にnullが入る場合で
missing使う場合は、結果をきちんと想像できるようにする。
それが不安な場合は
①class変数を単体で指定して、何回も回す
②欠損値を99などのダミー値にして回す
の方がまだいいかもですね。

また、たまにN数を_FREQ_からとっているプログラムをみますが、
もしN=と_FREQ_が常に同値と思ってやっているなら、それはヤバいです。

data Q2;
CL1=1;CL2=1;X=.;output;
CL1=1;CL2=1;X=.;output;
CL1=1;CL2=.;X=.;output;
CL1=2;CL2=2;X=.;output;
CL1=2;CL2=2;X=.;output;
CL1=2;CL2=.;X=.;output;
run;

proc summary data=Q2;
 types CL1 CL2;
 class CL1 CL2 / missing;
 var X;
 output out=A5 n=N;
run;










_FREQ_は純粋に読み込まれたオブザベーション数で、N=はそのうち、
varで指定された変数の値が非欠損値であるものの数です。

以上。今年も有難うございました!!

今年は無料のSAS Universityがリリースされ、アクセス履歴をみるとacドメイン(大学)が少し増えてきていて、Rが猛威を振るう中、少しでも新規の若いSASユーザーが増えるというのは、僕にとっては幸せを感じるできごとです(Rもできた方が絶対いいと思うけど)。

そういう新ユーザーが、SAS面白いって思えるような何かを提供するのが先達の務めだとも少しは思うので(一部のデータステップマニア向けで、あんまりそういう人向けのブログではないのですが…)、来年もまあ、頑張りたいと思います。

SASユーザー躍進の一年になりますように!!

2 件のコメント:

  1. 今年も大変お世話になりました!
    電王戦にも誘っていただいて、楽しかったです。

    来年も面白いもの見つけていきましょう!
    2015年も、どうぞよろしくお願いいたします。

    よいお年を!

    返信削除
  2. こちらこそ今年も大変お世話になりました!
    電王戦楽しかったですね!ちなみに今日も森下九段がツツカナとリベンジマッチやってます。
    また来年のFINALも行きましょうね!
    RWIについてのamatsuさんの論文発表、まじに考えてくださいね。楽しみです。

    よいお年を!!

    返信削除