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

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オプションで結果ビューアと同じ組み合わせの数に減らせます。


2017年2月23日木曜日

頻度集計で存在しない水準値を0件として出したい【PROC SUMMARY編】



まずは失敗例から。

失敗例
*** サンプルデータ作成 ;
data DT1;
input NO$ YN SEX;
cards;
001 1 2
002 1 2
;

YN…何かの有無(0=無、1=有)
SEX…性別(1=男、2=女)




*** FORMAT作成 ;
proc format;
   value _YN
   0 = "無"
   1 = "有"
   ;
   value _SEX
   1 = "男"
   2 = "女"
   ;
run;

*** 変数YN, SEXの頻度集計 ;
proc freq data=DT1;
   tables YN SEX;
   format YN _YN. SEX _SEX.;
run;




変数YNとSEXの頻度集計をしています。

その際、YNに以下フォーマットを当てています
「0=無」「1=有」

SEXには以下フォーマットを当てています
「1=男」「2=女」

結果を見てみると、「YN=0 (無)」と「SEX=1(男)」の度数が出てませんね。
これは集計対象のデータセットDT1に該当の値が存在しないからです。



PROC FREQでは現状0件の水準を出せないので、PROC SUMMARYで出してみましょう。
※今回の例は「1変数毎の頻度集計」のみに対応しています
※また、集計対象が0オブザベーションの場合、今回紹介するオプションは機能しません。

proc summary data=DT1 print completetypes;
   class YN SEX / preloadfmt missing;
   format YN _YN. SEX _SEX.;
   ways 1;
run;


POINT1

PROC MEANSでも似たようなことが出来るけど、PROC SUMMARYを使った理由。
それは、以下の記事を見ると理解しやすいと思います。


ちょっと解説すると、2つのプロシジャの違いのひとつが「VARステートメント」を省略した場合。
  • PROC MEANS: CLASSステートメント等、その他のステートメントに指定していない「すべての数値変数の要約統計量」が求められる
  • PROC SUMMARY:「オブザベーション数」のみ求められる

今回は頻度集計を求めたいだけなので、PROC SUMMARYが最適というわけです。
(ちなみにPROC SUMMARYでは「PRINT」オプションを指定しないと出力結果が表示されません)


POINT2

サンプルプログラムで指定している「COMPLETETYPES」「PRELOADFMT」「WAYS」については以下の記事を見て頂くと理解しやすいと思います。


ちなみにCLASSステートメントに「MISSING」をつけているのは以下データステップ100万回で解説されている落とし穴予防の為です(今回の例では問題ないけど)

2015年8月4日火曜日

SUMMARYプロシジャによる楽々転置法



サンプルデータ
data DT1;
input A$ B C$;
cards;
001 10 aa
001 20 bb
001 50 cc
002 . dd
002 100 .
002 200 ee
;






サンプルから、以下のようなデータセットを作りたいとします。
(Aの値毎に各変数値を横に転置しています。)







今回個人的にハマってるSUMMARYプロシジャで色々調べていたら、海外のSAS Global Forumで発表された方法が面白かったので、この方法で転置してみます。
http://support.sas.com/resources/papers/proceedings10/102-2010.pdf


SUMMARYプロシジャのIDGROUPを使った方法
proc sort data=DT1;
   by A;
run;

proc summary data=DT1 ;
   by A;
   output out=OUT1 (drop=_TYPE_ _FREQ_)  idgroup( out[3] (B C)= );
run;


これだけ!
IDGROUPについては以下で紹介しました。
MEANSまたはSUMMARYプロシジャで使えるIDGROUPオプションの紹介

最初、上のリンク記事の例のようにIDGROUPには min(変数) とか max(変数) を書く必要があるのかと思ったらそうでもないんですね!



汎用性をもたせるために、Aのグループ内obs数の最大値を取得して、その数だけ横に並べるようにしたプログラムが以下になります。
proc sql noprint;
   select max(_COUNT) into:_MAX trimmed from
   (select count(*) as _COUNT from DT1 group by A);
quit;

proc sort data=DT1;
   by A;
run;

proc summary data=DT1 ;
   by A;
   output out=OUT2 (drop=_TYPE_ _FREQ_)  idgroup( out[&_MAX] (B C)= );
run;


※ ただし、制限として1つの変数につき横に並べられるのは100個までとなります。
※ 「by A」を「class A」と書くと、合計行が作られてしまうので、必ず「by A」と書いてください。




2015年7月30日木曜日

集計結果をデータセット化する場合、MEANSよりSUMAMYプロシジャの方が効率的



サンプル作成

data DT1;
input A B @@;
cards;
3 10  2 20  1 30
;



SUMMARYプロシジャでAの平均値とBの平均値を求めてデータセットに出力したいとします。
これはOUTPUTステートメントに以下の書き方をするだけでokです。

proc summary data=DT1;
   output out=OUT1  mean(A)=A_MEAN  mean(B)=B_MEAN;
run;



構文

OUTPUT OUT=出力データセット名  統計量( 対象変数 ) = 出力変数名 ・・・;



MEANSプロシジャでも同じ書き方が出来るけど、、

proc means data=DT1 noprint;
   output out=OUT1  mean(A)=A_MEAN  mean(B)=B_MEAN;
run;


MEANS vs SUMMARYプロシジャ」で解説した通り、

MEANSプロシジャでは「VARステートメントを省略すると、CLASSステートメント等のその他のステートメントに指定していない全ての数値変数」が裏で集計されているようで、

SUMMARYプロシジャの方が、余計な集計が行われないし、短い文で書けるので効率的です。


2015年7月29日水曜日

MEANS vs SUMMARYプロシジャ



大人しく控え目な性格のSUMMARYプロシジャは、MEANSプロシジャの影に隠れがちです。
この2つは、ほとんど同じ挙動をしますが、ほんのちょっと違います。


サンプルデータ
data DT1;
input A B;
cards;
1 125
2 10
3 20
;



違い①

以下はMEANS と SUMMARYプロシジャによる実行結果ですが、同じ結果が得られます。

proc means data=DT1 ;
   var A;
run;

proc summary data=DT1 print;
   var A;
run;




異なる点として、SUMMARYプロシジャは「PRINTオプション」を付けないと集計結果が画面に表示されません。

proc summary data=DT1 ;
   var A;
run;

ログ
ERROR: PRINTオプションまたはOUTPUTステートメントがありません。
NOTE: エラーが発生したため、このステップの処理を中止しました。



違い②

以下はVARステートメントを省略した場合の集計結果です。

proc means data=DT1 ;
run;







proc summary data=DT1 print;
run;


VARステートメントを省略すると、、
  • MEANSプロシジャ: CLASSステートメント等、その他のステートメントに指定していない全ての数値変数が集計される。
  • SUMMARYプロシジャ: OBS数が算出される。

SUMMARYプロシジャの方が全体的に最小限の動きしかしていない感じでですね。
まずは今回紹介した性質の違いを覚えておきましょう。



SUMMARYプロシジャが役に立つ例




2015年7月28日火曜日

MEANSまたはSUMMARYプロシジャで使えるIDGROUPオプションの紹介


最近のお気に入りオプションなので紹介したいと思います。

サンプルデータ
data DT1;
input A B$;
cards;
2 aa
1 bb
3 cc
2 dd
. ee
;

サンプルに対して以下のプログラムを実行すると、、
proc summary data=DT1;
   output out=OUT1 idgroup( max(A) out[5] (A B)= );
run;

なんか横一行のデータが出来ました。

IDGROUPオプションの中に注目してみましょう。
max(A) out[5] (A B)=」 で変数Aが大きい順に行を並べ、上位5行のAとBの値をそれぞれ横に転置して表示するようなイメージです。

大きい順で同値がある場合(今回の例では、1行目と4行目のAが両方2)、オブザベーションの並び順で参照していきます(1行目、4行目の順で参照していく)。


注意点1
上の例で「max(A)」だけだとAが欠損値のオブザベーションは選択されません(今回の例では5行目)
欠損値のやつも引っ張ってきたい場合、以下の通りmissingオプションを追加します。

proc summary data=DT1;
   output out=OUT1 idgroup( max(A) missing out[5] (A B)= );
run;

また「min(A)」とすれば変数Aが小さい順になります。


注意点2
制限として1つの変数につき横に並べられるのは100個までのようです。