2017年4月24日月曜日

プロシジャで変数ラベルに改行を入れる方法



プロシジャ毎に方法が異なるので、それぞれ例をあげていきます。


PROC SQL の場合

以下で使用方法や注意点などを紹介済です。
PROC SQLでの変数ラベルの挙動

proc sql;
 select AGE "#ねん#れい"
 from SASHELP.CLASS;
quit;




PROC PRINT の場合

SPLIT=オプションでラベルの改行文字を設定できます。
以下の例では「#」を改行文字に設定していますが、適当な半角の英数・記号を設定可。

proc print data=SASHELP.CLASS noobs label split="#";
 var AGE;
 label AGE="ねん#れい";
run;


ちなみに「SUMLABEL=」や「GRANDTOTAL_LABEL=」で設定したラベルの場合は改行じゃなくてスペースが挿入されます。



PROC REPORT の場合

SPLIT=オプションが使えます。挙動はPROC PRINTのとは少し異なります。
以下で使用方法を紹介済です。

proc report data=SASHELP.CLASS nowd split="#";
 column AGE;
 define AGE / display "ねん#れい";
run;



別の方法も以下で紹介しています。



その他のプロシジャの場合

ODS LISTING以外の、一部の出力先(ODS HTML, RTFとか)では、インラインフォーマットというものを使って改行できます。
こちらも以下で使用方法や注意点などを紹介済です。
ODS出力時に文字の書式設定をする【インラインフォーマット】

proc freq data=SASHELP.CLASS;
 tables AGE;
 label AGE="ねん(*ESC*){newline 1}れい";
run;



2017年4月20日木曜日

複数のSQL文は、ひとつのPROC SQLにまとめて書くことが出来る


以下のように複数のPROC SQLを別々に書きがちですが、、、

* SQL① ;
proc sql;
   create table DT1 as
   select SEX, count(*) as C
   from SASHELP.CLASS
   group by SEX;
quit;

* SQL② ;
proc sql;
   create table DT2 as
   select AGE, count(*) as C
   from SASHELP.CLASS
   group by AGE;
quit;


ひとつのPROC SQL内でまとめて書くことが出来ます。

proc sql;

   * SQL① ;
   create table DT1 as
   select SEX, count(*) as C
   from SASHELP.CLASS
   group by SEX;

   * SQL② ;
   create table DT2 as
   select AGE, count(*) as C
   from SASHELP.CLASS
   group by AGE;

quit;


こちらの方が文もスッキリするし、処理効率も良いと思います。

2017年4月18日火曜日

PROC REPORTで困ったときのLISTオプション




REPORTプロシジャは非常に奥が深いので、以前より書いている「REPORTプロシジャ入門」でも基本部分さえ書ききれていません。


奥が深いゆえに「あれ?なんでこれうまく動いてくれないの!?」って質問も多くいただくので、そういった時に役立つLISTオプションをご紹介します。


とりあえず適当に以下LISTオプションをつけて実行してみます。

proc report data=SASHELP.CLASS nowd list;
  column NAME AGE;
run;


すると、ログにREPORTプロシジャの文が出力されます。

ログ
 PROC REPORT DATA=SASHELP.CLASS LS=132 PS=60  SPLIT="/" CENTER ;
 COLUMN  ( Name Age );
  
 DEFINE  Name / DISPLAY FORMAT= $8. WIDTH=8     SPACING=2   LEFT "Name" ;
 DEFINE  Age / SUM FORMAT= BEST9. WIDTH=9     SPACING=2   RIGHT "Age" ;
 RUN;


これは実行したREPORTプロシジャをSASがどのように解釈しているか表しています。
プログラマが省略したオプションとかが補完されて見れるわけですね。



REPORTプロシジャのオプションは初期値のクセが強いので「え?裏でそんな動きしてたのか、そりゃ想定通りの動きをしなかったわけだ。。」っていう具合にLISTオプションが解決の手助けをしてくれます。


ただし、ログに出力されるREPORTプロシジャの文には、
  • 一部の出力先でしか有効でないオプションが出力されたり(例えば「WIDTH=」や「SPACING=」というオプション)
  • 以下のような一部のステートメントやオプションの記述が省略されるらしいのでご注意ください
BY
WHERE
FREQ
WEIGHT
LIST
OUT=
OUTREPT=
PROFILE=
REPORT=
NOWD 
...等


2017年4月10日月曜日

変数「_NAME_」「_LABEL_」があるとPROC TRANSPOSEの挙動が変わる


以下をご覧ください。

例①
* サンプルデータ ;
data DT1;
   A=1; output;
   A=2; output;
run;
  A   
  1 
  2 


* TRANSPOSE ;
proc transpose data=DT1 out=OUT1;
  var A;
run;
 _NAME_ 
  COL1  
  COL2  
  A   1   2 

TRANSPOSEで変数Aを横に転置しています。


では上記のサンプルデータに以下の_NAME_という変数を追加して、再度同じようにTRANSPOSEしてみます。

例②
* サンプルデータ ;
data DT2;
  A=1; _NAME_="aa"; output;
  A=2; _NAME_="bb"; output;
run;
  A   
  _NAME_   
  1   aa 
  2   bb


* TRANSPOSE ;
proc transpose data=DT2 out=OUT2;
 var A;
run;
 _NAME_ 
  aa  
  bb  
  A   1   2 

例①の結果と異なっているのがお分かりいただけますか。
例①では変数名が「COL1」「COL2」だったのが、例②では「aa」「bb」という変数名になりました。

まるで以下のようにIDステートメントを使ったような挙動ですね。

proc transpose data=DT2 out=OUT2;
  var A;
  id _NAME_;
run;

実はTRANSPOSEするデータセットに「_NAME_」という変数があって、IDステートメントも未指定の場合、勝手に上記青文字の処理がされるようになっています。


では次は「_LABEL_」という変数を追加して、同様にTRANSPOSEしてみます。

例③
* サンプルデータ ;
data DT3;
  length A 8. _NAME_ $2. _LABEL_ $20.;
  A=1; _NAME_="aa"; _LABEL_="あああ"; output;
  A=2; _NAME_="bb"; _LABEL_="いいい"; output;
run;
  A   
  _NAME_   
  _LABEL_  
  1   aa   あああ
  2   bb  いいい


* TRANSPOSE ;
proc transpose data=DT3 out=OUT3;
 var A;
run;
 前の変数名 
  あああ 
  いいい  
 _NAME_ 
  aa  
  bb  
  A   1   2 
※1段目が変数ラベル、2段目が変数名



結果を見ると変数ラベルがついています。まるで以下のように書いたときの挙動ですね。

proc transpose data=DT3 out=OUT3;
  var A;
  id _NAME_;
  idlabel _LABEL_;
run;

これも「_LABEL_」という変数があって、IDLABELステートメントも未指定の場合、勝手に上記赤文字の処理がされるようになっています。

これを「勝手なことしやがって!」と思うか、「便利だな」と思うかケースバイケースですね。

以下記事のように2回TRANSPOSEを実行する場合は特に気をつけましょう。
TRANSPOSEの2回実行テクニック。


2017年4月3日月曜日

「ORDER=FORMATTED」の落とし穴




前回の記事でORDER=オプションを紹介しました。
http://sas-boubi.blogspot.jp/2017/03/order_28.html


このオプションで一番注意しなければならないのが、「ORDER=FORMATTED」を指定した場合です。
以下の例が想定通りの結果になるか各自確認してみてください。




「ORDER = FORMATTED」 の挙動確認

* サンプルデータ ;
data DT1;
input A @@;
cards;
1 1 1.5 1.5 2 2
;












* PROC FREQで「ORDER=FORMATTED」 ;
proc freq data=DT1 order=formatted;
  tables A;
run;


あれ!?
特にフォーマットも割り当ててないし、「1→1.5→2」の順になるかと思ったら「1→2→1.5」になってる。。



原因

何故かというと、、
(ここから推測ですので間違ってるかもしれないのであしからず。)

以下のプログラムで変数Aに割り当てられているフォーマットをログに出力してみると、

data _null_;
  set DT1;
  x=vformat(A);
  put x;
  stop;
run;

ログ
BEST12.


数値変数の場合、フォーマットが割り当てられていないと、内部的にBEST12.があてられているっぽい?
では、PUT関数を使って、変数AをBEST12.で文字変換してみましょう。

data DT2;
  set DT1;
  length A2 $20.;
  A2 = put(A,best12.);
run;


文字変換したA2を見ると、以下のように先頭に半角スペースが入ってしまいます。
1    → "           1"
1.5 → "         1.5"
2    → "           2"

この文字変換したA2でソートしてみると、、

proc sort data=DT2;
  by A2;
run;


文字値によるソート&先頭の半角スペース込みのソートなので、本来の数値の順番にソートがされないって事ですね。




プロシジャ毎にORDER=オプションのデフォルト設定が違う

「ORDER=INTERNAL」がデフォルトになっているプロシジャが多い中、いくつか例外があります。

例えばPROC REPORTです。
SAS9.4 (2016/4/3現在) では、デフォルトが「ORDER=FORMATTED」に設定されています。

proc report data=DT1;
 column A;
 define A / group;
run;








proc report data=DT1;
 column A;
 define A / order;
run;


順番おかしいですね。フォーマットではなく変数値の順に並べ替えたい場合は、以下のように「ORDER=INTERNAL」を別途指定します。

proc report data=DT1;
 column A;
 define A / group order=internal;
run;

proc report data=DT1;
 column A;
 define A / order order=internal;
run;

SAS9.4のリファレンスには、PROC REPORTのORDER=は他のプロシジャと整合とるために今後のリリースでデフォルト設定を変えるかも、というような記述があるので、この点も要注意ですね。