ラベル プロシジャ: FREQ の投稿を表示しています。 すべての投稿を表示
ラベル プロシジャ: FREQ の投稿を表示しています。 すべての投稿を表示

2017年9月13日水曜日

ODS OUTPUT の落とし穴 (1)



まず以下うまくいく例をご覧ください。

うまくいく例
ods output OneWayFreqs=OUT1;

   proc freq data=SASHELP.CLASS;
      tables SEX AGE;
   run;

ods output close;



次にうまくいかない例。

うまくいかない例
ods output OneWayFreqs=OUT1 (where=(AGE=13));

   proc freq data=SASHELP.CLASS;
      tables SEX AGE;
   run;

ods output close;

ログ
ERROR: 変数AGEはファイルWORK.OUT1にありません。


WHERE=オプションを追加したらERRORが出ちゃいました。
構文的には問題ないのに何故でしょう?



原因


以下のように ODS TRACE で出力オブジェクト名をログに表示してみると、、

ods trace on;

proc freq data=SASHELP.CLASS;
   tables SEX AGE;
run;

ods trace off;

ログ
出力の追加 :
-------------
名前 :         OneWayFreqs
ラベル :       一元表
テンプレート : Base.Freq.OneWayFreqs
パス :         Freq.Table1.OneWayFreqs
-------------

出力の追加 :
-------------
名前 :         OneWayFreqs
ラベル :       一元表
テンプレート : Base.Freq.OneWayFreqs
パス :         Freq.Table2.OneWayFreqs

出力オブジェクト「OneWayFreqs」が2つ出てますね。

PROC FREQ の TABLESステートメントで「tables SEX AGE」と書いているため、
SEXとAGEそれぞれに出力オブジェクト「OneWayFreqs」が出来ている事を表しています。



そしてここから予想になるのであしからずという感じですが、

ods output OneWayFreqs=OUT1 (where=(AGE=13));

   proc freq data=SASHELP.CLASS;
      tables SEX AGE;
   run;

ods output close;

と書いたときの挙動として、

① 変数 SEX の集計結果をデータセット OUT1 に出力
② 変数 AGE の集計結果をデータセット OUT1 に出力

となりますが、どうやらWHERE=オプションは上記①②のそれぞれで実行されている気がします(色々実験した結果の予想)

つまり①の時点では出力データセットに 変数 AGE の集計結果が存在していないので、「where=(AGE=13)」は ”存在していない変数に対するWHERE条件” となりERRORが出てしまったというわけですかね。

PROC FREQに限らず、同じ名前の出力オブジェクトが複数出力されるようなケースでは同様に注意が必要です。



内部挙動は予想になってしまうので、
この辺ちゃんと説明しているサイトなどご存知の方いたら教えて下さい。


ちなみに、以下記事でその他の落とし穴も紹介しています。
「ODS OUTPUT」の落とし穴 (2)

2017年3月21日火曜日

欠損値の分類も集計に含めるMISSINGオプションと落とし穴



多くの集計用プロシジャでは、分類変数が欠損値のオブザベーションを集計から除きます。



サンプルデータ

data DT1;
input A B C;
cards;
1 1 10
. 1 10
2 1 10
. 1 10
;


変数Aには欠損値が含まれてます。



分類に欠損値が含まれている場合の集計結果

proc freq での例

proc freq data=DT1;
   tables A * B;
run;









変数Aの欠損値2オブザベーションが集計から除かれています。
欠損値も含め集計したい場合、missingオプションをつけます。

proc freq data=DT1;
   tables A * B / missing;
run;



同様に proc means や proc summary でもclass変数が欠損値のオブザベーションは集計から除かれます。
missingオプションをつけるとclass変数が欠損値のものも含め集計されます。

proc means data=DT1;
   class A / missing;
   var C;
run;


proc tabulateも同様。

proc tabulate data=DT1;
   class A / missing;
   table A;
run;




落とし穴①

まずは、proc freq の「なんじゃそりゃ」という落とし穴(proc means や proc tabulateでは問題なさそう)
以下の例をご覧ください。

proc format;
   value A_
      . , 1 = "Missing and One"
      2 = "Two"
   ;
run;

proc freq data=DT1;
   tables A * B;
   format A A_.;
run;



変数Aに欠損値と1をまとめた "Missing and One" というフォーマットを設定して集計しています。
missingオプションを設定していないので、欠損値は集計から除かれますが、なんと、、A=1も欠損値の扱いになって集計から除かれています。

フォーマットで欠損値と非欠損値を1つのカテゴリにまとめた場合、
実データに欠損値が存在すると、同じカテゴリの非欠損値のデータも巻き込んで、欠損値の扱いにしてしまうようです。



落とし穴②

既にSASYAMAさんが記事にされているので、そちらをご覧ください。
means summaryプロシジャのclassステートメント指定変数の欠損値には気を付けてって話

classステートメントに変数を複数指定する場合は注意という話です。
class変数のいずれかに欠損値が含まれている場合、missingオプションがないとそのオブザベーションが全ての集計から除かれてしまいます。



落とし穴③

これも上のSASYAMAさんの記事で注意喚起されていますが、
proc means や proc summary の outputステートメントで集計結果をデータセットに出力すると、

proc means data=DT1;
   class A B / missing;
   var C;
   output out=OUT1 n= mean= / autoname;
run;

集計結果:結果ビューア

集計結果:出力データセットOUT1

出力データセットの方は、結果ビューアにない組み合わせも出力されています。
例えば、出力データセットの1行目は変数AとBの分類全体に対する集計結果です(ただしmissingオプションがない場合、変数AかBが欠損値のオブザベーションは除いたうえで集計される)

特にmissingオプションを設定していると、どの組み合わせに対する集計なのか、分かりづらいです(例:1行目と3行目)


変数_TYPE_で上記の違いを区別することが出来るものの、「紛らわしいので要らない!」というケースがほとんどなので、、

proc means data=DT1 nway;
   class A B / missing;
   var C;
   output out=OUT1 n= mean= / autoname;
run;

nwayオプションで結果ビューアと同じ組み合わせの数に減らせます。


2016年3月18日金曜日

SASで頻度集計とクロス集計 【FREQプロシジャ】




構文 : 頻度集計

PROC  FREQ  DATA=対象データセット;
       TABLES  対象変数  ;
RUN;

対象変数が欠損値のオブザベーションは集計から除かれます。
欠損値も含めるには「TABLES  対象変数  /  MISSING;」と指定します。



proc freq data=SASHELP.CLASS;
     tables AGE ;
run;







構文 : クロス集計

PROC  FREQ  DATA=対象データセット;
    TABLES  表側変数 *  表頭変数 ;
RUN;

表側または表頭変数が欠損値のオブザベーションは集計から除かれます。
欠損値も含めるには「TABLES  表側変数 * 表頭変数  /  MISSING;」と指定します。




proc freq data=SASHELP.CLASS;
     tables SEX * AGE;
run;


度数, パーセント, 行のパーセント, 列のパーセントが出力されます


対象変数が欠損値のオブザベーションが集計から除かれる件の詳細は以下参照。
http://sas-boubi.blogspot.com/2017/03/missing_21.html


2014年12月5日金曜日

FREQプロシジャのLISTオプションで、変数値同士の組み合わせを見易くする。




データの組み合わせなどを確認する際に役立つ、ちょこっとしたオプションを紹介。

*** Sample Data ;
data DT1;
input CODE$ NAME$;
cards;
001 AAA
004 DDD
003 BBB
001 AAA
004 DDD
002 CCC
002 CCC
;

 CODE 
NAME
  001  
  AAA  
  004
  DDD  
  003
  BBB  
  001
  AAA  
  004
  DDD  
  002
  CCC  
  002
  CCC  


たとえば、上のサンプルで「CODEとNAMEの値の組み合わせを調べたい」ってなったとします。


そこでまずはFREQを使ってみます。

proc freq data=DT1;
   tables CODE * NAME / missing;
   format _all_;
run;




これでもいいけど、もうちょっと変数値同士の組み合わせを見やすくしたいので、、

proc freq data=DT1;
   tables CODE * NAME / missing list;
   format _all_;
run;


「LISTオプション」を追加するとリスト形式になって、確認しやすくなりました。


ちなみに、以下の設定も忘れずに!
  • 変数に欠損値があった場合、欠損値も水準に含めるため「MISSINGオプション」を設定
  • formatをあてた値の組み合わせではなく、変数値の組み合わせを見たい場合「FORMAT _ALL_」で全変数にあてられたformatを解除。


📝 1つ気をつけたいのが、、

例えば、以下の例

data DT2;
   X="   AAA"; output;
   X="BBB"; output;
run;

proc freq data=DT2;
   tables X / missing list;
   format _all_;
run;



データセットDT2の1行目の変数Xの値は「   AAA」って感じで先頭に半角スペースが含まれていますが、
FREQの出力結果を見ると、この半角スペースが削除されて表示されていますよね。

プロシジャの結果がHTML形式等で表示される際、先頭の半角スペースを除く仕様みたいです。

こんな感じで、格納値の通りに表示されない場合があるので、
データクリーニングとか、ちゃんと格納値を確認したい場合は、今回の機能だけじゃなくて、FREQをかける前の元データを目視確認したり、改行・文字化け・余計なスペース等のおかしなデータを検出するチェックプログラムを作ったり、別途確認が必要です。



てことで、あんまり使わなそうな機能でも、覚えておくと今回のようにちょっとした事で役立つという話でした。
SASに無駄な機能なしです。



2014年10月15日水曜日

全オブザベーション欠損値の変数を削除する


たとえば、以下サンプルデータで、削除したい変数は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;

 A  
 B  
 C  
 D  
  .
  1
  
  1
  .
  1
  
  2
  .
  .
  
  3

欲しい結果
 B  
 D  
  1
  1
  1
  2
  .
  3

そこで、データステップ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

注目してほしいのは「非欠損水準(NNonMissLevels)」で、これが0ってことはその変数は全オブザベーションが欠損値ということですよね。


②次にプログラムを生成・実行してくれるCALL EXECUTEを使い、上で取得した非欠損水準が0の変数をDROPするプログラムを生成します。

生成されるプログラムは以下のような感じ。

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でありがちな落とし穴」)


2014年6月2日月曜日

FREQプロシジャ のWARNINGメッセージ「期待度数が5より小さくなっています。」の制御方法



まず以下のプログラムを見てみましょう。

*** サンプルデータ作成 ;
data DT1;
input A B C;
cards;
1 1 2
1 2 4
2 1 1
2 2 5
;


*** Fisherの正確検定 ;
proc freq data=DT1 noprint;
   tables A*B / exact ;
   weight C / zeros;
   output out=OUT1 exact ;
run;


ログ
WARNING: セルの75% (表 : A * B)において、期待度数が5より小さくなっています。カイ2乗検定は妥当な検定でないと思われます。



カイ2乗検定で「期待度数が5未満のセル」の比率が20%より大きい場合に上記のようなログが出ます。



カイ2乗検定を行う場合、状態を把握するためにも、このログは出力させておいたほうが良いと思います。
しかし今回の例では、はじめからFISHERの正確検定だけをやりたいのに、自動でカイ2乗検定の結果も出るため、このWARNINGは今回は見ないため、なくしたい。

そんな時にNOWARNオプションでこのログを制御できます。

*** Fisherの正確検定 ;
proc freq data=DT1 noprint ;
   tables A*B / exact  nowarn ;
   weight C / zeros;
   output out=OUT1 exact  ;
run;



またカイ2乗検定を出すときに「WARN=OUTPUT」と記述すると、、

*** カイ2乗検定 ;
proc freq data=DT1 noprint ;
   tables A*B / chisq   warn=output ;
   weight C ;
   output out=OUT1 chisq ;
run ;


「期待度数が5未満のセル」の比率が20%より大きいかどうかのフラグ変数を出力データセットに作成してくれます。
(SAS環境によって異なりますが「カイ2乗値のWarning」みたいなラベルでフラグ変数が作成されます)