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

2023年5月7日日曜日

「PROC REPORT」の「COMPUTE」がうまく動かないんだけど②



以下記事の続き。



失敗例1

data test;
input x y;
cards;
. 10
. 20
1 30
1 40
2 50
2 60
;
proc report data=test missing spanrows;
  column x y z;
  define x / order order=internal;
  define y / display;
  define z / computed;
  compute z / character length=1;
    if x=. then z="Y";
  endcomp;
run;
😕


  • まず、XをORDER変数にしています。またORDER変数が欠損値のオブザベーションも出力対象とするため、MISSINGオプションを指定。
  • 次にCOMPUTEで「if x=. then z="Y"」として、Xが欠損値のオブザベーションに"Y"のフラグを立てたんですが、、想定では1、2オブザベーション目だけに"Y"が入るはずなのに、4、6オブザベーション目にも"Y"が入っている?!


XをORDER変数にしたことが影響してると思うんですが、リファレンスにこの辺の挙動の説明見つけられませんでした。

ORDER変数(GROUP、ANALYSIS、ACROSS変数とかも?)を参照した処理(IFステートメントや関数など)は想定通りの結果にならないことがあるので、使用は避けたほうが良さそうです。




失敗例2

proc report data=test missing spanrows;
  column x y;
  define x / order order=internal;
  define y / display;
  compute x;
    if x=. then x=2;
  endcomp;
run;
😕


「if x=. then x=2」として、「Xが欠損値」の場合は「X=2」のオブザベーションとして以下のように一塊で出力したかったのに、、


あと、失敗例①を知っちゃうと、なんとなく以下のようになるのでは?と思っちゃいません?(失敗例①で「X=.」と判定されたオブザベーションが、今回「X=2」になると思ってしまった)



ORDER変数(GROUP、ANALYSIS、ACROSS変数とかも?)に対して、COMPUTEで値をいじると、うまく絡み合ってくれなくて、想定外の結果になる場合があるのでご注意ください。

そもそも元の変数値をPROC REPORT上でいじるのって、あまりやらない、というか良くないのかも?




あと未検証ながら


以下リファレンス内の「Restriction」の記載によると、、

よく分からないですが、LAG, DIF, RANUNI, DATETIMEなどの「non-deterministic関数」については、特定条件のときに使わない方が良いらしいです。


COMPUTE、難しいよーー!



2019年7月19日金曜日

「PROC REPORT」の「COMPUTE」がうまく動かないんだけど




以下の失敗例をご覧ください。

* 失敗例 ;
proc report data=sashelp.class;
    column name age;
    compute age;
        if age=13 then call define("age","style","style=[color=blue]");
    endcomp;
run;


「AGE=13だったらAGEの文字色を青にする」というのがやりたかったのに、青になってないじゃん、っていう失敗例です。




解説


さて、何がまずかったでしょうか。
まずは以下の前提知識が必要なのでお目通しを。。

REPORTプロシジャ入門4:集計【ANALYSIS】
REPORTプロシジャ入門10:数値変数の落とし穴



上のリンクの入門記事でも解説した通り、

REPORTプロシジャに指定した ”数値項目” は、以下のように「analysis sum」オプションが勝手について実行されます。

proc report data=sashelp.class;
    column name age;
    define name / display;
    define age / analysis sum;
run;



analysis項目ではなく普通の表示項目にしたい場合は、displayオプションを指定します。
以下の通り、display項目であればうまく書式設定できます。

proc report data=sashelp.class;
    column name age;
    define age / display;
    compute age;
        if age=13 then call define("age","style","style=[color=blue]");
    endcomp;
run;




もし意図的にanalysis項目のままにしたい場合、computeの中で以下のように「項目名.統計量」という書き方をする必要があります。

proc report data=sashelp.class;
    column name age;
    compute age;
        if age.sum=13 then call define("age.sum","style","style=[color=blue]");
    endcomp;
run;




2017年10月3日火曜日

【PROC REPORT】1つの項目に複数のCALL DEFINEを定義したい




「CALL DEFINEの重ね着って出来ないんですか?」って質問をたまにいただきます。


どういう事かと言うと、以下の例をご覧ください。

proc report data=SASHELP.CLASS nowd;
    column NAME AGE ;
    define NAME / display;
    define AGE / display;
    compute AGE;
       if AGE > 13 then call define( "name", "style", "style=[color=blue]" );
       if AGE > 14 then call define( "name", "style", "style=[background=yellow]" );
    endcomp;
run;

CALL DEFINEで、

① AGE>13の時、変数NAMEの値を青色にする
② AGE>14の時、変数NAMEの背景色を黄色にする

という事をしてます。

よくみると、Janetさんは値を青にした上で、背景色を黄色にしたかったんですが、青くなってません。


CALL DEFINEで定義したSTYLEが、1つのセルに対して1つしか適用されていないようです。
STYLEの適用順は状況によって異なりますが、今回は「①値を青色」→「②背景色を黄色」の順で適用されているようですね。



そこで、小技。
以下のように「STYLE/MERGE」とすれば、複数のCALL DEFINEによるSTYLEを、上書きじゃなくてMERGE(結合)してくれます。

proc report data=SASHELP.CLASS nowd;
    column NAME AGE ;
    define NAME / display;
    define AGE / display;
    compute AGE;
       if AGE > 13 then call define( "name", "style", "style=[color=blue]" );
       if AGE > 14 then call define( "name", "style/merge", "style=[background=yellow]" );
    endcomp;
run;

ちゃんとJanetさんが青くなってますね。


ちなみに、
本題からズレますが、CALL DEFINEを書くために利用しているCOMPUTEステートメントは高頻度でうまく設定できないケースを見かけるので、以下記事と以下記事内にリンクしている記事も要確認です。




📝その他、混乱しそうなポイント

以下みたいに一方が「_ROW_」だと、「STYLE/MERGE」としなくても1つのセルに複数のSTYLEが設定できました。

proc report data=SASHELP.CLASS nowd;
    column NAME AGE ;
    define NAME / display;
    define AGE / display;
    compute AGE;
       if AGE = 14 then call define( "name", "style", "style=[color=blue]" );
       if AGE = 14 then call define( _row_, "style", "style=[background=yellow]" );
    endcomp;
run;


ただ、以下の場合ちょっと混乱しそう。

proc report data=SASHELP.CLASS nowd;
    column NAME AGE ;
    define NAME / display;
    define AGE / display;
    compute AGE;
       if AGE = 14 then call define( "name", "style", "style=[color=blue]" );
       if AGE = 14 then call define( _row_, "style", "style=[color=red]" );
    endcomp;
run;


最後「_ROW_」で行の全変数の文字色を赤にしたはずなのに、NAMEの文字色が青になってる?
プログラムの記述順で、STYLEが適用されると思いがちですが、違うっぽい。
2番目の以下「_ROW_」のSTYLEが先に実行されて、、

 if AGE = 14 then call define( _row_, "style", "style=[color=red]" );


次に1番目の以下STYLEが適用されたような挙動です。

 if AGE = 14 then call define( "name", "style", "style=[color=blue]" );



本題から逸れましたが、こんな感じで動きが独特なのでご注意ください。


2017年9月25日月曜日

【PROC REPORT】RTF出力時の細かい罫線の設定



PROC REPORTでRTF出力する際に、セル毎の細かい罫線(色・太さ・線種)を設定する方法を紹介します。



まず罫線の設定を表すスタイル属性は以下の3つです。



罫線のスタイル属性

  設定内容  指定   指定できる値
 罫線の色 

 BorderxxColor = 
  
 black, white …など 

 罫線の幅
(太さ)

 BorderxxWidth =
 

 1pt, 2pt …など


 罫線の線種  

 BorderxxStyle =

 dashed, dotted, double, hidden, solid …など 


xx部分にはセルのどの位置の罫線を設定するか指定
「Right」「Left」「Top」「Bottom」が入る




例① 特定の列に罫線を引く


工程1
まずは以下の記事で紹介している方法でざっくりとレポート全体の罫線の引き方を変更します。

(PROC TEMPLATEで全体の罫線やフォントをあらかじめ設定しといてもOK)

ods rtf file='出力するRTFファイルのフルパスを指定';

proc report data=sashelp.class nowd
           style(report)=[rules=groups frame=hsides]
           style(header)=[background=white];
   column name sex age ;
   define name / display;
   define sex / display;
   define age / display;
 run;

ods rtf close;


工程2
次に個別に細かい罫線を引いていきます。
たとえば、変数NAME の右に縦罫線を入れたいとします。

以下の記事も参考に罫線を入れてみます
REPORTプロシジャ入門8:書式の設定【STYLE=】

ods rtf file='出力するRTFファイルのフルパスを指定';

proc report data=sashelp.class nowd
           style(report)=[rules=groups frame=hsides]
           style(header)=[background=white];

   column name sex age ;
   define name / display style(header column)={BorderRightColor=black
                                                                BorderRightStyle=double
                                                                BorderRightWidth=1pt};
   define sex / display;
   define age / display;
run;

ods rtf close;




例② 特定の行に罫線を引く


以下の記事を参考に「AGE > 13」の行だけセルの下に罫線を引いてみます。
REPORTプロシジャ入門9:特定セルの書式設定【CALL DEFINE】

(例で使用しているCOMPUTEステートメントは、高頻度でうまく設定できないケースを見かけるので、上記記事と上記記事内にリンクしている記事も要確認)

ods rtf file='出力するRTFファイルのフルパスを指定';

proc report data=sashelp.class nowd
           style(report)=[rules=groups frame=hsides]
           style(header)=[background=white];

   column name sex age ;
   define name / display;
   define sex / display;
   define age / display;
   compute age;
        if age > 13 then
                call define(_row_,"style","style(calldef)={BorderBottomColor=black
                                                                                BorderBottomStyle=solid
                                                                                BorderBottomWidth=1pt}");
   endcomp;
run;

ods rtf close;




例③ 2段以上のヘッダーの罫線

以下をご覧ください。

ods rtf file='出力するRTFファイルのフルパスを指定';

proc report data=sashelp.class nowd
           style(report)=[rules=groups frame=hsides]
           style(header)=[background=white];
   column name ("Height and Weight" height weight);
   define name / display;
   define height / display;
   define weight / display;
run;

ods rtf close;


上のレポートで、ヘッダーが2段になっている「Height and Weight」の下に罫線を引きたいとします。


以下記事を参考に罫線を入れてみます。
ODS出力時に文字の書式設定をする【インラインフォーマット】

ods rtf file='出力するRTFファイルのフルパスを指定';

proc report data=sashelp.class nowd
           style(report)=[rules=groups frame=hsides]
           style(header)=[background=white];

    column name ("(*ESC*)S={BorderBottomColor=black
                                             BorderBottomStyle=solid
                                             BorderBottomWidth=1pt}Height and Weight"  height weight);
   define name / display;
   define height / display;
   define weight / display;
run;

ods rtf close;



2017年5月23日火曜日

REPORTプロシジャ入門10:数値変数の落とし穴



前提知識として、まず以下リンク記事をご覧ください。
REPORTプロシジャ入門4:集計【ANALYSIS】




では、落とし穴の例を見ていきましょう。


落とし穴の例


データセットSASHELP.CLASS の NAME, AGE をREPORTプロシジャで出力してみます。

* 例① ;
proc report data=SASHELP.CLASS nowd;
   column NAME AGE;
   define NAME / "名前";
   define AGE  / "年齢";
run;


まぁ、これは特におかしなところはないですね。
では以下のように年齢だけ出力してみるとどうでしょうか?


* 例② ;
proc report data=SASHELP.CLASS nowd;
   column AGE;
   define AGE  / "年齢";
run;


「あれ?1行しか出力されていないうえ、年齢「253」てなんだよ!」って感じですよね。




解説


実は、REPORTプロシジャに指定した ”数値変数” は、以下青字のように「analysis sum」オプションをSASが裏で勝手につけて実行しています。

proc report data=SASHELP.CLASS nowd;
   column AGE;
   define AGE  / analysis sum "年齢";
run;


つまり、AGEを合計して「253」という出力になってしまったわけですね。


以下のように「display」オプションを明示的につければ、この勝手な挙動を制御できます。

proc report data=SASHELP.CLASS nowd;
   column AGE;
   define AGE  / display "年齢";
run;



ちなみに最初の例①の場合は、SASが裏で以下青字のように判断して実行します。

proc report data=SASHELP.CLASS nowd;
   column NAME AGE;
   define NAME / display "名前";
   define AGE    / analysis sum "年齢";
run;


文字変数の場合は特にこちらで明示しない場合「display」が勝手につくわけです。

つまり挙動として、数値変数 AGE だけだと合計してしまうけど、文字変数 NAME を「display」オプションでそのまま表示するようにしているから、AGE も合計されなくて済んでるっていう仕組みです。
(AGE が「全ての行」の合計ではなく、行ごとに「その行の1つの数値だけ」で合計する、という意味のない動きになっていて、結果的に格納値そのままの値になる)



9.特定セルの書式設定【CALL DEFINE】
10:数値変数の落とし穴

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月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=は他のプロシジャと整合とるために今後のリリースでデフォルト設定を変えるかも、というような記述があるので、この点も要注意ですね。



2017年3月3日金曜日

PROC REPORTでRTF出力時に小数点の位置を揃える方法



※RTF以外の出力先では、今回紹介するオプションが機能しない場合があるのでご注意ください。


*** サンプルデータ作成 ;
data a;
input a b$;
cards;
90.1 90.1
100 100
12.3 12.3
;
run;


*** RTF出力時に小数点の位置をそろえる ;
ods rtf file="適当なパス\test.rtf";
proc report data=a;
  column a b;
  define a / display style(column) = [ width=80 textalign=dec ];
  define b / display  style(column) = [ width=80 textalign=dec ];
run;
ods rtf close;


styleオプションで「textalign=dec」を指定すると小数点の位置を揃えて出力します(「just=d」と書いてもOK)
便利なのが、上のデータでは変数Bは文字変数なのに小数点位置を揃えてくれている点です。

2017年2月14日火曜日

PROC REPORTで先頭の半角スペースを保持する方法(ODS出力時)



ちょっと前に以下の記事を書きました。
PROC REPORTでインデントをつける方法(ODS出力時)


そして昨日マニュアル読み漁ってたら違う方法みつけました。
ちなみに「ODS RTF」での例になります。その他の出力先でも今回の方法が使用できるかはリファレンスをご確認下さい。


以下のような、先頭に半角スペースが入っている変数があったとします。

* Sample data ;
data dt1;
length a $3.;
a="aaa";output;
a=" bb";output;
a="ccc";output;
a=" dd";output;
run;

aaa 
 bb  
ccc  
 dd 


そして以下、変数Aのデータ部分の先頭の半角スペースを保持する例
(注意事項があるので下の説明もご覧下さい)

ods rtf file="出力するRTFファイルのフルパス";
proc report data=dt1;
  define a / display  style(column) = {asis = on};
run;
ods rtf close;

styleオプションの「asis=on」で先頭の半角スペースを保持してくれます。
(注意: ちなみに変数値に改行が含まれてる場合、改行も保持するようになります)


また、全変数のデータ部分に対してこのオプションを適用したい場合は、以下のように書きます。

ods rtf file="出力するRTFファイルのフルパス";
proc report data=dt1 style(column) = {asis = on};
  define a / display;
run;
ods rtf close;


2016年11月17日木曜日

PROC REPORTでヘッダーを改行するもう一つの方法



以下記事で、ヘッダーを改行する方法を紹介しました。
REPORTプロシジャ入門2:ヘッダーの設定



別の方法として、以下のように書いてもヘッダーを改行できます。
青字部分は通常の改行の書き方で、赤字部分が今回紹介したかった書き方)

proc report data=sashelp.class split="#";
   column name age;
   define name /  display  "ABC#DEF#GHI";
   define age    /  display  "ABC" "DEF" "GHI";
run;



PROC REPORTで、表示する変数の数が多い場合に分割(ページを分ける)方法



PROC REPORTの「PAGEオプション」と「IDオプション」を紹介します。


早速ですが、
以下は特定の変数のところでページを分割する例です。

ods rtf file="出力ファイルのフルパス";

   proc report data=sashelp.class;
       column name sex age height weight;
       define name / display;
       define sex / display;
       define age / display;
       define height / display page;
       define weight / display;
   run;

ods rtf close;




PAGEオプションを指定した変数のところで、ページ分割されます(上の例では変数HEIGHTのところで分割)

注意点として、
他のオプションとの組み合わせによってはPAGEオプションが動作しない場合があります。
また、LISTING出力先とそれ以外の出力先とで挙動に差異があるようです。
詳細はSAS社リファレンスのPAGEオプションのところをご確認下さい。
SAS Help Center: Syntax: PROC REPORT DEFINE Statement



続いて、PAGEオプションと併用すると便利なIDオプションの例。
以下は変数NAME, SEXを「ID変数」として、各ページの左側に固定で表示させています。

ods rtf file="出力ファイルのフルパス";

   proc report data=sashelp.class;
       column name sex age height weight;
       define name / display;
       define sex / display id;
       define age / display;
       define height / display page;
       define weight / display;
   run;

ods rtf close;



COLUMNステートメントに指定された変数の順に「1列目の変数」~「IDオプションを指定した変数」までを、各ページの左側に固定で表示させています。



2016年2月18日木曜日

グループ毎に空白行を追加したい



やりたい事

* サンプルデータ ;
data DT1;
length NO SEX $10. AGE HEIGHT 8.;
input NO$ SEX$ AGE HEIGHT @@;
cards;
001 F 25 159.2  002 F 43 161.8  003 F 21 158.1  004 M 19 178.0  005 M 28 160.2
;



変数SEXの値ごとに1行だけ空白行を追加したいとします。




方法① データステップ

proc sort data=DT1;
   by SEX ;
run ;

data OUT1;
   set DT1 ;
   by SEX ;
   output ;
   if last.SEX then do ;
       call missing( NO, AGE, HEIGHT );
       output ;
   end ;
run ;


ざっくり解説すると、
  • output;」でいったん現在のオブザベーションをデータセットに出力
  • if last.SEX then do;」で、SEXの値「F」「M」ごとに最後のオブザベーション(3obsと5obs)を読み込んだ時に、
  • call missing( NO, AGE, HEIGHT )」で変数NO, AGE, HEIGHTを欠損値にして、
  • output;」でデータセットに再出力しています。


📝注意点

ここで使用している「LAST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かない事があります(解説記事:「サブセット化IFでありがちな落とし穴」)





方法② REPORTプロシジャ

proc report data=DT1 out=OUT2 nowd ;
   define _numeric_  / display ;
   define SEX  / order order=internal missing ;
   break after SEX  / ;
run ;


REPORTプロシジャってデータセットにも出力できるんです!

  • define SEX / order order=internal missing;」と「break after SEX /;」で、SEX毎に要約行を追加
    • この書き方、HTML等への出力時には要約行が入らないんですが、データセット出力時には要約行が入ります
  • このままだと要約行に数値変数AGE, HEIGHTの要約値(合計)が入ってしまうので、「define _numeric_ / display;」で全数値変数を集計せずただdisplayするだけ(表示するだけ)にしています(データセット中に数値変数が存在しないなら「define _numeric_ / display;」は不要)
  • out=OUT2」でデータセットOUT2に出力


他に何かいいアイディアがあれば教えてください!


2016年2月15日月曜日

REPORT(またはPRINT)プロシジャで罫線の引き方を設定する。


※ ODS RTF, PDF等、一部の出力先でのみ設定できます。詳細はリファレンスを参照下さい。
(設定可能なはずの一部のODS出力先で正しい動きをしない場合があったので、各自、各環境でテストしたほうが良さそうです)



構文


 PROC REPORT  STYLE( REPORT )=[ RULES=設定1  FRAME=設定2 ];
 RUN;



RULES = 内側の罫線
 指定 設定内容
 NONE  罫線なし 
 COLS   縦罫線のみ 
 ROWS  横罫線のみ 
 ALL   縦横すべて 
 GROUPS  表ヘッダーとデータの切り替わり部分に罫線を引く。
 データと表フッターの切り替わり部分にも罫線を引く 。
 表ヘッダーや表フッターがないと罫線は引かれない。

 FRAME = 外側の罫線
 指定 設定内容 
 VOID 罫線なし 
 ABOVE   上のみ 
 BELOW  下のみ 
 LHS   左のみ 
 RHS  右のみ 
 HSIDES 上下のみ   
 VSIDES  左右のみ 
 BOX  上下左右 





ods rtf file="出力パスを指定\TEST.rtf";

proc report data=SASHELP.CLASS(obs=5)
         style(header)=[background=white]
         style(report)=[rules=groups frame=hsides] ;
   column SEX NAME AGE;
   define SEX / display;
   define NAME / display;
   define AGE / display;
run;

ods rtf close;





関連

REPORTプロシジャ入門8:書式の設定【STYLE=】
【PROC REPORT】RTF出力時の細かい罫線の設定

2016年2月10日水曜日

REPORTプロシジャ入門9:特定セルの書式設定【CALL DEFINE】




前回 「書式の設定【STYLE=】」 の応用。
「CALL DEFINE」 で、特定の行または列だけ書式を設定する事ができます。



基本構文

COMPUTE  対象変数;
           CALL DEFINE( "対象変数", "STYLE", "STYLE=[スタイル設定]");
ENDCOMP;


諸注意
  • STYLE=は、ODS LISTGNG出力先には対応していないので、ご注意下さい。
  • CALL DEFINEを複数定義すると、うまく適用できない場合があります(記事の最後に関連記事のリンク貼ってます)



では、例をみていきます。



列の書式設定 ①

proc report data=SASHELP.CLASS nowd;
    column NAME AGE ;
    define   NAME  / display;
    define   AGE    / display;
    compute AGE;
       call define( "AGE", "style", "style=[color=blue]" );
    endcomp;
run;


以下のように「_COL_」と書いてもOK

    compute AGE;
       call define( _COL_ , "style", "style=[color=blue]" );
    endcomp;

(こう書くと、COMPUTEステートメントに書かれた変数AGEが対象になる。)




列の書式設定 ②

proc report data=SASHELP.CLASS nowd;
    column NAME AGE HEIGHT;
    define   NAME    / display;
    define   AGE       / display;
    define   HEIGHT  / display;
    compute AGE;
       if AGE > 13 then call define("NAME","style","style=[color=blue]");
    endcomp;
run;


ここで注意!
NAMEに対する書式設定ですが、「compute NAME;」 ではなく 「compute AGE;」と指定しています。
なぜかというと、、以下ルールに従っているからです。


①  COMPUTEステートメント内で使われている変数はAGEとNAMEです。
②  このAGEとNAMEのうち、COLUMNステートメントで一番後ろに指定されている変数はAGEです。
③  よって 「compute AGE;」 とする。

ちなみに「compute HEIGHT;」としてもOK。
(COLUMNステートメントでHEIGHTの方がNAMEやAGEより後ろに指定されているから)




行の書式設定

proc report data=SASHELP.CLASS nowd;
    column NAME AGE HEIGHT;
    define   NAME    / display;
    define   AGE       / display;
    define   HEIGHT  / display;
    compute AGE;
       if AGE > 13 then call define( _ROW_, "style", "style=[color=blue]" );
    endcomp;
run;

_ROW_」で該当の行全体に対して書式設定を行います。



📝ちなみに、、

CALL DEFINEを複数定義すると、うまく適用できない場合があります。
【PROC REPORT】1つの項目に複数のCALL DEFINEを定義したい


インラインフォーマットを組み合わせると、更に自由度の高い書式設定が行えます。
ODS出力時に文字の書式設定をする【インラインフォーマット】


最後にCOMPUTEステートメントを使う上で超重要&ありがちな落とし穴もあるので、ちょっと前提知識必要になるけど、是非ご覧ください。
「PROC REPORT」の「COMPUTE」がうまく動かないんだけど
「PROC REPORT」の「COMPUTE」がうまく動かないんだけど②



REPORTプロシジャ入門記事一覧

1.基本構文【COLUMN, DEFINE】
2.ヘッダーの設定
3.並べ替え・グループ化【ORDER, GROUP】
4.集計【ANALYSIS】
5.転置集計【ACROSS】

2016年2月1日月曜日

REPORTプロシジャ入門8:書式の設定【STYLE=】



ODS LISTING以外の、ODS RTF, HTML, PDF等の出力先では、STYLEオプションを使ってセルの書式設定ができます。


構文

STYLE(  設定場所  ) = [ 書式1  書式2 ・・・]


設定場所
 指定 設定場所 
 HEADER   ヘッダー(項目名) 
 COLUMN   中身のデータ 
 SUMMARY   要約行
 ・・・など    


書式
・「設定場所」によっては書式設定が効かない場合あり
・RTF, HTML等の出力先毎に設定可能な書式が違うのでリファレンスも要参照
指定設定内容 例 
FONTFAMILY  フォント fontfamily='MS P明朝'
FONTSIZE文字サイズfontsize=10pt
FONTWEIGHT 文字の太さfontweight=bold
FONTSTYLE斜体等のスタイル fontstyle=italic
COLOR文字色color = blue
BACKGROUNDCOLOR  セル色backgroundcolor = yellow 
WIDTHセルの横幅width = 3cm
指定した幅にならない場合あり
HEIGHTセルの高さheight = 3cm
指定した高さにならない場合あり
TEXTALIGN文字の横位置textalign = left
VERTICALALIGN文字の縦位置verticalalign = center
 ・・・ など




では、例を見ていきます。
以降の例は、HTMLへの出力が有効になっている前提です。


レポート全体の書式設定

proc report data=SASHELP.CLASS nowd style(column)=[color=blue];
   column  NAME AGE;
   define  NAME / display;
   define  AGE    / display;
run;





項目ごとの書式設定

proc report data=SASHELP.CLASS nowd;
   column  NAME AGE;
   define  NAME  / display style(column) = [color=blue] ;
   define  AGE     / display style(header) = [background=yellow] ;
run;





ちなみに、、


以下のように HEADER や COLUMN などは一度に複数定義できます。
*OK;
define  NAME / display style(header) = [background=yellow]
                                   style(column) = [color=blue]  ;



また、PRINTプロシジャ等、一部のプロシジャでもSTYLEオプションが使えちゃいます。
proc print data=SASHELP.CLASS ;
   var NAME /  style(column)=[color=blue];
   var AGE;
run;

📝

2016年1月25日月曜日

PROC REPORTでグループ毎に空白行を挿入する。



以下は変数SEXの値毎に、空白行を挿入しています。

proc report data=SASHELP.CLASS nowd spanrows;
     column SEX NAME AGE;
     define SEX     / order order=internal missing;
     define NAME  / display;
     define AGE    / display;
     compute after SEX;
        line "";
     endcomp;
run;


  • 変数SEXに対して、ORDERオプションでデータの並び替えを設定。
  • COMPUTE内でLINEステートメントを入れることで空白行を挿入しています。

REPORTプロシジャ自体については入門記事を参照ください。

2016年1月22日金曜日

REPORTプロシジャ入門7:計算項目の追加【COMPUTE】




COMPUTEステートメントについて解説していきます。
重要な注意事項を含むので、ひと通り記事全体をご覧ください。



簡単な例

proc report data=SASHELP.CLASS nowd;
   column NAME HEIGHT WEIGHT FLAG;
   define NAME     / display;
   define HEIGHT  / display;
   define WEIGHT / display;
   define FLAG      / computed;
   
   compute FLAG;
      if HEIGHT > 65 or WEIGHT > 100 then FLAG = 1;
   endcomp;
run;



計算項目「FLAG」を作り、「HEIGHT > 65」or「WEIGHT > 100」の場合に「1」を格納しています。



構文解説

まずは作成する項目をCOLUMNステートメントに指定

   column NAME HEIGHT WEIGHT FLAG;


計算項目であることをDEFINEステートメントに定義しておきます
(「COMPUTED」と指定)

   define FLAG   / computed;


計算内容を「COMPUTE」~「ENDCOMP」内に記述します。
IF文や関数なども使えます。

   compute FLAG;
      if HEIGHT > 65 or WEIGHT > 100 then FLAG = 1;
   endcomp;



重要なのが「COLUMNステートメント」での「計算項目」の指定場所
「計算項目」は、計算時に参照しているどの項目よりも後に指定するのが安全


今回の例で説明すると、
「FLG」の計算には、「HEIGHT」「WEIGHT」を参照しています。

   compute FLAG;
      if HEIGHT > 65 or WEIGHT > 100 then FLAG = 1;
   endcomp;



なので、COLUMNステートメントでは「HEIGHT」「WEIGHT」の後に「FLAG」を指定しています。

   column NAME HEIGHT WEIGHT FLAG;


(SASが内部で処理する順番が関係していそうですが、内部の話なので、明確な理由が説明できません。。)




文字項目を追加する例

proc report data=SASHELP.CLASS nowd;
   column NAME SEX NEWVAR;
   define NAME      / display;
   define SEX         / display;
   define NEWVAR  / computed;
   
   compute NEWVAR / character length=20;
      NEWVAR = compress( NAME || "-" || SEX );
   endcomp;
run;



「NAME」と「SEX」を横棒でつないでくっつけた計算項目「NEWVAR」を作っています。



計算項目が文字の場合は、COMPUTEステートメントで以下のようにLENGTHを定義しておきます。

  COMPUTE  計算項目名  /  CHARACTER LENGTH = 長さ ;