幾何平均の出し方がちょっとずつ増えてるけど、誰も気づきませんって!という話

9.4からメンテナンスリリースのバージョンによる機能の差がちょっと目立つようになってきた。
プログラムを他の環境に渡して、ゴリゴリ動かすことが想定されているなら
メンテナンスリリースのバージョンまで、移管先とすり合わせておいた方がよくなってきそう。


ちなみに、自分の使っているSASのメンテナンスリリースのバージョンがわからない場合は

proc product_status;
run;

を実行してみるとよいですよ。











9.4_M3と、でてるM3の部分がメンテナンスレベル3を示してます。
だから、BASEのリファレンスをググッて、参照する場合はthird editionとついているやつを見た
方が正確です。
あとSAS/STATのバージョンも重要で14.1とでていますので、BASEにない統計系のプロシジャ
を参照する場合は14.1のものを見てくださいということですね。

9.3→9.4とかの大きなバージョンアップの場合は、多くのユーザーはSASがだしている
what's newを参照してからプログラムしてると思うので(してますよね?)いいんですけど、
メンテナンスリリースは、一応上がるたびに最新に更新してアップされているとはいえ
その辺をくまなくチェックしてるユーザーは少ないかも。

最近ちょっとびっくりしたのが9.4M3で、univariateに幾何平均の指定がこっそりと増えていたこと。
なんでいまさら!しかもメンテナンスリリースレベルのアップでいきなり!
正直に言わせて頂くと…、誰も気づかねぇよ!!

9.1でgeomean関数が追加されて、横持の変数の幾何平均がだせるようになり
9.2でttestプロシジャでだせるようになり
9.4M1でsurveymeansが対応して
9.4M3でunivariateが対応して(信頼区間などはでない)…

いや、まどろっこしいから、普通にproc meansに幾何平均がらみの統計キーワード
全部追加してくださいよ


/*9.4M3から univariateでgeomeanが指定可能*/
proc univariate data=sashelp.class;
var weight;
output out=out1 geomean=geomean;
run;


/*9.4M1からsurveymeansでgomean、その他信頼区間も指定可能*/
proc surveymeans data=sashelp.class geomean gmclm gmstderr lgmclm ugmclm;
var weight;
ods output GeometricMeans=out2;
run;


/*9.2からttestでlognormalを指定して幾何平均と信頼区間がだせる*/
proc ttest data=sashelp.class dist=lognormal;
  var weight;
  ods output Statistics=out3;
run;



/*9.1からgeomean関数で幾何平均がだせる*/
proc transpose data=sashelp.class out=temp1;
var weight;
run;
data out4;
set temp1;
geomean=geomean(of COL:);
keep geomean;
run;



/*9.1以前*/
data temp2;
set sashelp.class;
         logval=log(weight);
RUN;
proc means data=temp2 noprint;
  var logval;
  output out=temp3 lclm=lcl mean=mean uclm=ucl;
run;
data out5;
  set temp3;
  lcl_gm = exp(lcl);
  geomean = exp(mean);
  ucl_gm = exp(ucl);
run;

title "univariate";
proc print data=out1 label;
run;









title "surveymeans";
proc print data=out2 label;
run;




title "ttest";
proc print data=out3 label;
run;




title "転置してからgeomean関数";
proc print data=out4 label;
run;










title "logとってからmeansかけてexp";
proc print data=out5 label;
run;



サンタクロースはいつプレゼントを買うのか

せっかくなんでクリスマスネタをやりたいと思いつつも、ツリー書いたり、雪降らせたり
とてもじゃないですが、matsuさんに太刀打ちできそうにないので、別のネタを。

自分の子供はまだ0歳なんで、あんまり関係ないのですが、世の中のお父さんサンタさん達は、いつ頃プレゼントを仕入れに行ってるのかなと疑問に思いました。

どうしましょうね。

日本にはe-statという、政府統計を誰でも自由に利用できる仕組みがあります。
そこで家計調査を選択し、2015年の二人以上の世帯の「第6-16表 1世帯当たり1か月間の日別支出」を2カ月分ほどEXCELで落としてきます。

ちなみに集計表によってはCSVで落とせたり、API叩いて落とせたりするんですが、今回はEXCELを読み込みます。

ダウンロードしたファイルを開いてみると、












わぁ、なんて素敵な神エクセルでしょう。
ユーザーが読み込んで使うかもしれない統計表をこういうレイアウトにするセンスに脱帽です。

データステップで激しく加工して、品目分類を「玩具」に絞ってプロットしてみます
(ちなみに玩具は「テレビゲーム機」「ゲームソフト等」「他の玩具」を含む分類です)

値自体は、子供のいない世帯も含む平均値なので、絶対的にはあまり意味ないです。
また、事前に予約しておいて、支払いは受け取り時だったりするケースや、クレジットの支払いがどうなっているのかなど
細かい話はおいておいて、傾向をざっくり見てみましょう。


libname ex11 "XXXXXXX\raw\a616_11.xls" mixed=yes header=no;
libname ex12 "XXXXXXX\raw\a616_12.xls" mixed=yes header=no;

data wk1;
set ex11.'6-16二人以上の世帯$'n(drop=F43 in=in1)
      ex12.'6-16二人以上の世帯$'n(in=in2)
;
where F9="玩具";
if in1 then month=11;
if in2 then month=12;

run;

proc transpose data=wk1 out=wk2;
  var F11-F42;
  by month;
run;

data wk3;
set wk2;
val=col1;
year=2015;
day=input(substr(_NAME_,2,2),?? best.)-10;
    date=mdy(month,day,year);
wd=choosec(weekday(date),'日','月','火','水','木','金','土',);
label=cats(put(day,z2.),wd);

if date ne .;
format date yymmdds10.;
keep date val label santa;
run;

title"品目分類835-837 玩具の支出";
proc sgplot data=wk3 noautolegend;
series x=date y=val;
text x=date y=val text=label;

xaxis values=("01NOV2015"d to "31DEC2015"d by 15 );
run;



































やっぱり12月に入ると、土日を中心に活発に活動してるみたいですね。
年比較すると、昔より購入時期が早くなってるのか?なども見えてくるかもですね。
予約時期はこのデータからだと見えませんが。
様式が面倒すぎてあまりやる気がおきませんが…。

データステップ内でプロシジャを動かして、その結果をキー結合するマクロ

最近思いついた、相当しょうもないアイデア。
書くのは恥だが役に…って類いのコード

例えば、以下のような3つのデータセットがあって

data A;
ID=1;SEX="M";GRP=1;output;
ID=2;SEX="F";GRP=1;output;
ID=3;SEX="M";GRP=3;output;
ID=4;SEX="F";GRP=2;output;
ID=5;SEX="F";GRP=2;output;
run;

data B;
ID=1;SEX="M";WEIGHT=75;output;
ID=2;SEX="F";WEIGHT=55;output;
ID=3;SEX="M";WEIGHT=65;output;
ID=4;SEX="F";WEIGHT=45;output;
ID=5;SEX="F";WEIGHT=85;output;
run;

data C;
GRP=1;HEIGHT=175;output;
GRP=1;HEIGHT=155;output;
GRP=1;HEIGHT=165;output;
GRP=2;HEIGHT=145;output;
GRP=2;HEIGHT=185;output;
run;

BでSEXごとに求めた要約統計量をSEXをキーにしてAに結合、
CでGRPごとに求めた要約統計量をGRPをキーにしてAに結合っていうような
処理を埋め込み系のマクロにして、1ステップ中にいくらでも入れれるようにしたいなと思いました。

ようするにこういうこと
data D;
set A;
%get_summary(dataset=B,key=SEX,var=WEIGHT)
%get_summary(dataset=C,key=GRP,var=HEIGHT)
run;

結果は(画像は途中まで)




で、肝心のマクロの中身は

%macro get_summary(dataset=,key=,var=);
%let qkey  = %sysfunc( tranwrd( %str("&key") , %str( ) , %str(",") ) );
length &var &var._SUM &var._MEAN &var._StdDev &var._MIN &var._MAX 8.;
call missing(of &var &var._SUM &var._MEAN &var._StdDev &var._MIN &var._MAX );
if _N_=1 then do;
rc=dosubl("proc summary data=&dataset nway;class &key;var &var.;
                         output out=temp sum= mean= std= min= max=/autoname");
declare hash h&sysindex.(dataset:"temp");
h&sysindex..definekey(&qkey);
h&sysindex..definedata("&var._SUM","&var._MEAN","&var._StdDev","&var._MIN"
                                         ,"&var._MAX  ");
h&sysindex..definedone();
rc=dosubl("proc delete data=temp;run;");
end;
if h&sysindex..find() ne 0 then call missing(of &var._SUM &var._MEAN &var._StdDev &var._MIN &var._MAX);
drop rc &var. ;
%mend get_summary;

知ってる人からしたら、なんだdosubl関数使うのか、そりゃできるでしょうよって馬鹿にされそう。

けど、まあ、当然に感じる人が大半かもしれないけど、ハッシュに格納する直前で、このタイミングでデータセット作って間に合うっていう感覚は個人的には斬新。

dosubl関数は、call executeと違って、データステップの途中で即時的に処理が開始できる特性があります。
なのでdosubl関数でデータセット作って、そのままハッシュに入れて、すぐ消してるんですね。小賢しい…
だから見かけ上は1ステップでも、速くはないです(mergeよりかは速いけど)。
あらかじめプロシージャ回してデータセット作ってからハッシュに格納するのと同じです。

本来これはDS2でやるか、ハッシュ内でループで計算してから繋ぐ書き方でやる処理なんですね…。

ちなみに、思いつきでパパッと書いたマクロなんで、使うならちゃんと検証してくださいね。
多分、穴はあると思います。まず、再帰ができない、ようするにset対象自身を指定できないとかね。
あと複数変数指定にも対応してないですね

あ、今書いてて思ったんですけど、この記事、SAS忘備録の
「データステップ内でプロシジャを実行する。」の焼き増しですね。
http://sas-boubi.blogspot.jp/2016/05/blog-post_17.html