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

縦に欠測値のカウントの話

ひとつ前の記事に書きましたが、SAS社様の公式TwitterやFacebookでこのブログを紹介していただきましたので、ちょっとお行儀よく、久しぶりに基本的かつ真面目な話題をします。

各変数ごとに欠測の値が何オブザベーションあるかを1ステップでカウントしたいとします。

要は

data Q1;
X=1;Y='';Z=.;output;
X=2;Y='A';Z=.;output;
X=3;Y='B';Z=.;output;
run;









上記みたいなデータセットから





を作りたいということです。


さて、ぱっと思い浮かびました?意外と難しかったりしませんか?

proc meansが思いついた方もいたと思いますが

proc means data=Q1 noprint;
 var X Z;
 output out=A0(drop=_TYPE_ _FREQ_) nmiss=XMISS ZMISS;
run; 

のように数値変数X Zに対してはnmiss=で欠損値カウントが可能ですが、文字値のYはvarに指定した時点でエラーになってしまいます。

freqが思いついた方もいるかもしれませんが、1ステップで、上記の形のデータセットを作るのは難しいはずです、多分。

基本、データを縦に考える時はSQL使えっていうのは僕の中の原則なので、

proc sql noprint;
 create table A1 as
   select sum(missing(X)) as XMISS
          ,sum(missing(Y)) as YMISS
          ,sum(missing(Z)) as ZMISS
       from Q1;
quit;

は、正解です。上記の回答データセットの結果になります。
missingは欠損値の場合1、非欠損値の場合0なので、それをsumで合計すればよいわけです。
わざわざcase文書かなくても、SASのmissing関数をSQLにぶち込めちゃうところがグレートですね!

次にこれぞSASのデータステップ!!って感じで書くなら

data A2;
 set Q1 end=eof;
 retain XMISS YMISS ZMISS 0;
  if missing(X) then XMISS+1;
  if missing(Y) then YMISS+1;
  if missing(Z) then ZMISS+1;
  if eof;
 drop X Y Z;
run;

で、結果は同じです。1行ずつ順番に読んでいくSASの正道って感じですね。

やっぱ上記のようなステップ書いてる時は、なんか居飛車、それも矢倉とか指してる感覚に似てますよね。逆にSQL書いてる時は、角交換系の振り飛車の間隔ですね。ハッシュオブジェクトもそれに近いけど、もしかしたら横歩取りの感覚かも。
僕はもちろん振り飛車党です。
結局脱線してるっていう




whichn関数はwhereステートメントでも使える話とその応用をだらだら

SASを勉強中のYさんから、たとえば以下のようなデータがあって

data Q1;
X=1;Y=2;Z=3;output;
X=2;Y=3;Z=4;output;
X=1;Y=5;Z=1;output;
X=2;Y=.;Z=4;output;
run;

XかYかZのいずれかが1であるデータを抽出するとき

data A0;
set Q1;
where X=1 or Y=1 or Z=1;
run; 

といったように横にひたすらorで同じ条件を変数だけ変えて書き連ねているのですが
もっとマシな書き方ありませんかと聞かれました。

多分、かなりいくらでもあると思うのですが、最近whichn(c)関数やchoosen(c)関数が
マイブームなので

data A1;
set Q1;
where whichn(1,X,Y,Z)>0;
run;

としました。

ただし難点としては

/*エラーになる*/
data E1;
set Q1;
where whichn(1,of X--Z)>0;
run;

whereステートメントで上記のような変数指定の仕方は通らないので一括指定で
どうしても抽出したいなら

data A1_;
set Q1;
if whichn(1,of X--Z)>0;
run;

サブセット化ifにする必要があります。

でも基本的にif抽出よりwhereの方が速いので、対象が巨大なデータの場合ifはお勧めできないかもしれません。


捜索対象がnullの場合whichn(c)関数は使えないので

where X=. or Y=. or Z=.;の場合は例えば

data A2;
set Q1;
where nmiss(X,Y,Z)>0;
run;

とでもしてください。


おまけ

SAS忘備録の「関数の小技」
http://sas-boubi.blogspot.jp/2014/02/blog-post_7.html

にインスパイアされて。

もし抽出条件が

X<1 or Y>=5 or Z^=4

のようにバラバラだった場合も

data OMAKE1;
set Q1;
where whichn(1,X<1,Y>=5,Z^=4);
run;

のように引数に式を入れると、真偽結果0、1が戻る性質を利用して、こんな風にかけちゃう。

で

data OMAKE1;
set Q1;
where whichn(1,X<1,Y>=5,Z^=4)>0;
A=whichn(1,X<1,Y>=5,Z^=4);
run;

割り当てとけば、どの条件に(最初に)合致して、抽出されたデータなのか確認できるので便利かも