たとえば、以下サンプルデータで、削除したい変数はAとCです。
*** サンプルデータ ; data DT1; A=.; B=1; C=""; D=1; output; A=.; B=1; C=""; D=2; output; A=.; B=.; C=""; D=3; output; run;
欲しい結果
|
そこで、データステップ100万回「freqプロシジャのnlevelsオプション」をヒントにプログラムを組んでみました。
*** ① 全OBS欠損値の変数を特定する ; ods output NLevels=O_NLEVEL; proc freq data=DT1 nlevels; tables _all_ / noprint; format _all_; run; ods output close; *** ② 特定した変数をDROPする ; data _NULL_;
length NNONMISSLEVELS 8. ;
set O_NLEVEL end=EOF; if _N_=1 then call execute( "DATA DT2; SET DT1 (DROP=" ); if NNONMISSLEVELS=0 then call execute( TABLEVAR ); if EOF then call execute( "); RUN;" ); run; |
解説
①まず、FREQプロシジャのNLEVELSオプションによって下のようなOUTPUTとデータセットが出来る。
OUTPUT
変数 水準数 欠損水準 非欠損水準
----------------------------------------------
A 1 1 0
B 2 1 1
C 1 1 0
D 3 0 3
データセット
TableVar
|
NLevels
|
NMissLevels
|
NNonMissLevels
|
---|---|---|---|
A
|
1
|
1
|
0
|
B
|
2
|
1
|
1
|
C
|
1
|
1
|
0
|
D
|
3
|
0
|
3
|
②次にプログラムを生成・実行してくれるCALL EXECUTEを使い、上で取得した非欠損水準が0の変数をDROPするプログラムを生成します。
生成されるプログラムは以下のような感じ。
DATA DT2; SET DT1 (DROP=
A
C
); RUN;
生成されるプログラムは以下のような感じ。
DATA DT2; SET DT1 (DROP=
A
C
); RUN;
同様の処理を沢山のデータセットにやりたい場合は、このプログラムをちょっと改良してマクロ化しちゃえば楽です。
単純に全オブザベーション欠損値の変数が知りたいだけでも、FREQプロシジャ+NLEVELSの組み合わせでいけちゃうので便利です。
📝注意
・変数に format が割り当てられている場合、
formatがあてられた値に対してNLEVELSが動いてしまい、思った動きをしてくれないことがある。そのため、FREQプロシジャのとこで「format _all_」でformatを解除しておいた方が良いです。
・対象のデータセットが空(0オブザベーション)の場合、FREQプロシジャのとこでつまづいてWARNINGが出ちゃってうまく動きません。
その辺も考慮しなきゃいけない場合は、「オブザベーション数=0なら~」みたいな条件分岐する文を追記する必要があります。
・今回のテクニックの中で使用している「_N_」と「END=オプション」は「サブセット化IF」と一緒に使用すると正しく動かなくなりやすいです。
(解説記事:「サブセット化IFでありがちな落とし穴」)
(解説記事:「サブセット化IFでありがちな落とし穴」)
どうもです。
返信削除データセットのO_NLEVELの中身の図の方に誤記があるかもです。
Dの行について1 1 0になってますが 3 0 3では?
リストの方はあってるはずです。
ところで100投稿目、おめでとうございます!!
一昨日も言いましたけど、これだけ役に立って、丁寧な記事を発信されているのは、本当に素晴らしいです。
困ったときに役に立つのは100万回ブログよりも忘備録ともっぱらの噂です。
これからもお互い頑張りましょう。
あっ寝ぼけてました!
削除ご指摘ありがとうございます!
ひっそりとした100投稿目になると思ってたので、コメントいただけて嬉しいです。
今回の投稿もSASYAMAさんの投稿からアイディアを頂きましたし、ほんと100万回ブログ参考になります。
これからもSASYAMAさんのブログタイトルにもなっている新手一生を掲げて、何か面白いアイディアやテクニックを発掘していきましょう!