僕の頁 <SASと臨床試験と雑談と>

徒然なるままにSAS暮らし

----

スポンサーサイト  

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Posted on --/--/-- --. --:-- [edit]

CM: --
TB: --

0814

続・RWI:ODS LAYOUTとの比較編  

前回に引き続き、RWIで遊んでみました。内容は例のごとくSAS忘備録で紹介されているもので、今回はODS LAYOUTによるグラフの出力をRWIでも実行してみました。出力内容は2013年のSASユーザー総会の「ODS LAYOUTによるワクチンの臨床開発におけるDashboardの作成」の例示の部分です(資料はユーザー登録すればSASプレミアムラウンジからダウンロード可能です)。
自動車関連の情報を格納したsashelp.carsデータセットを用いて、馬力、価格、燃費等を要約した4個のグラフを白黒で2行2列のレイアウトに出力します。
①ODS LAYOUTで出力
2x2のグリッドを定義して、PDFファイルに4個のグラフを出力する。この際に作成したグラフを所定のフォルダに保存しておく(ods listingのgpathオプション、imagenameオプション)。
②RWIで出力
①で保存した画像ファイルを2x2のレイアウトで出力する。

まずは白黒スタイル作成部分。SAS9.4では以前紹介したstyleattrsステートメントを使用すればSGプロシジャ内で定義できますが、ここでは分けて記述します。
options nocenter nodate nonumber papersize=A4 orientation=landscape nofmterr mprint ;

*** グレースケール用のスタイルテンプレート ;
proc template ;
define style Mystat ;
parent=styles.statistical ;
class Graphdata1 /
contrastcolor = black linestyle = 1 linethickness = 1px markersymbol = "trianglefilled" foreground = CXdcdcdc ;
class Graphdata2 /
contrastcolor = black linestyle = 1 linethickness = 1px markersymbol = "circlefilled" foreground = CXb7b7b7 ;
class Graphdata3 /
contrastcolor = black linestyle = 1 linethickness = 1px markersymbol = "diamondfilled" foreground = CX808080 ;
class Graphdata4 /
contrastcolor = black linestyle = 1 linethickness = 1px markersymbol = "triangle" foreground = CX555555 ;
class Graphdata5 /
contrastcolor = black linestyle = 1 linethickness = 1px markersymbol = "circle" foreground = CX3f3f3f ;
class Graphdata6 /
contrastcolor = black linestyle = 1 linethickness = 1px markersymbol = "diamond" foreground = black ;
end ;
run ;

続いて、メインのグラフ作成部分です。まずODS LAYOUTで出力し、RWIではimageメソッドで作成した画像ファイルを指定してPDFに出力します。
*** 1. ODS LAYOUTのグリッドでグラフを出力する ;
ods graphics on / width=5.3in height=3.5in imagename="test" ; *--- testという名前の連番で画像ファイル保存 ;
ods listing gpath="/test" style=Mystat dpi=150 ; *--- 画像ファイル作成の際に白黒適用 ;
ods pdf file="/test/test.pdf" style=Mystat nogtitle dpi=150 ; *--- PDF出力に白黒適用 ;

title "ODS LAYOUT statement" ;
ods layout start columns=2 rows=2 ; *--- 2x2のグリッドを定義 ;
ods region ; *--- 1個目の領域 ;
proc sgpanel data=sashelp.cars ;
panelby TYPE / novarname ;
hbar Origin / response=Horsepower group=Origin stat=mean datalabel dataskin=gloss ;
label Horsepower="Horsepower (ps)" ;
format Horsepower 7.1 ;
run ;

ods region ; *--- 2個目の領域 ;
proc sgplot data=sashelp.cars ;
hbar Origin / response=MSRP group=Type stat=sum datalabel dataskin=gloss groupdisplay=cluster ;
label MSRP="MSRP($)" ;
run ;

ods region ; *--- 3個目の領域 ;
proc sgplot data=sashelp.cars ;
vbar Origin / response=MPG_City group=Type stat=mean datalabel dataskin=gloss groupdisplay=cluster ;
label MPG_City="Miles per Gallon" ;
format MPG_City 7.1 ;
run ;

ods region ; *--- 4個目の領域 ;
proc template ;
define statgraph CreatePie ;
begingraph ;
layout region ;
piechart category=Type response=MSRP
/ group=Origin groupgap=5 dataskin=sheen name="pie" ;
discretelegend "pie" / border=true ;
endlayout ;
endgraph ;
end ;
run ;

proc sgrender data=sashelp.Cars template=CreatePie ;
run ;

title ;

ods layout end ;
ods pdf close ;
ods graphics / reset=all ; *--- filenameの連番リセットだけならreset=index ;

*** 2. 上記で作成したグラフをRWIで出力する ;
ods pdf file="/test/test2.pdf" style=Mystat dpi=150 ;
title "layout_gridded method in RWI" ;
data _null_ ;
dcl odsout rwi() ;
rwi.layout_gridded(rows: 2,columns: 2) ; *--- 2x2のグリッドを定義 ;
rwi.region() ; *--- 1個目の領域 ;
rwi.image(file: "C:\test\test.png") ; *--- 1個目のグラフ(画像ファイル) ;
rwi.region() ; *--- 2個目の領域 ;
rwi.image(file: "C:\test\test1.png") ; *--- 2個目のグラフ(画像ファイル) ;
rwi.region() ; *--- 3個目の領域 ;
rwi.image(file: "C:\test\test2.png") ; *--- 3個目のグラフ(画像ファイル) ;
rwi.region() ; *--- 4個目の領域 ;
rwi.image(file: "C:\test\test3.png") ; *--- 4個目のグラフ(画像ファイル) ;
rwi.layout_end() ;

run ;
title ;
ods pdf close ;

結果は以下になります。titleが異なるのと、少しだけODS LAYOUTのほうが綺麗に出力されている気がしますが、dpiも同じ値にしてるし理由は分かりません。また、ODS LAYOUTでは当然ながらグラフの作成と出力が同時に実行できますが、今回の例のように、RWIは一度グラフを画像ファイルで保存しておくしかないのだとしたら、ひと手間余計に掛かってしまうことになります。もしDATAステップの中でSGPLOTを実行して出力ファイルをRWIで使用できるなんていう離れ業が1ステップで実現できれば、RWI以外にも様々な可能性が広がりそうですね。
RWI_02_1.png
RWI_02_2.png
スポンサーサイト

Posted on 2015/08/14 Fri. 01:28 [edit]

CM: 0
TB: 0

0812

Report Writing Interface (RWI)を試してみる  

SASによるレポート作成機能は豊富に用意されていて、一つ一つ挙げていくとキリがありませんが、SAS忘備録で詳細に解説されているReport Writing Interface (RWI)を試してみました。評価版ではこれまでも使用できたみたいですが、恥ずかしながら存在を知りませんでした。レポートの作成については、tabulateプロシジャやreportプロシジャ、templateプロシジャ、ODS等の組み合わせで大抵カバーできると感じていて、何となくマンネリ化して新しいものを取り入れるモチベーションに欠けておりましたが、SAS忘備録のせいで片足突っ込んでしまいました。ちなみにSAS忘備録の人はそのままSASユーザー総会でRWIをポスター発表されており、立ち話ついでに少しだけご指導して頂きました。この場を借りて御礼申し上げます。

詳細はSAS忘備録に任せますが、大ざっぱに言うと、RWIは、DATAステップで、スタイルのカスタマイズを含めてtemplateプロシジャや単純なreportプロシジャの機能を実現できるものです。最大のメリットは、やはり「DATAステップ」という点でしょう。if文等、データの条件に応じてDATAステップの文法で出力レイアウト等を指定できるため、ロジックを組み立てる上で他の方法よりはるかに理解しやすいと思います。もちろんtemplateプロシジャやreportプロシジャでも同様のことはできるのですが、cellstyle asやcompute等、それぞれDATAステップとは異なる条件分岐の文法を習得する必要があります。

注意点というか残念な点は、RWIは、Printer Family、つまり通常使うフォーマットだと、PDF出力にしか対応していないようなので、業務でRTFではなく、PDF出力が必須の方がメインのユーザーとなるでしょう。

今回は、臨床試験において継時的に測定された体重変化量の要約表を作成します。
1. テストデータ作成
2. summaryプロシジャで変化量の要約統計量を算出
3. レポートの作成(①templateプロシジャのみ、②reportプロシジャのみ、③RWIのみ)
という流れでプログラムを作成します。

レポートは上記3種類で出力してみます。Style Templateを明示的に指定するのは①のみです。

<レポートの作成要件>
・表のタイトルは表の上に出力し、左寄せで下線のみ。
・"Summary Statistics"を要約統計量の代表タイトルとして要約統計量の上部真ん中に出力。
・VisitとTreatmentのヘッダーの上だけ罫線を引かない。
・罫線は基本行ごとに出力するが、Visitは重複出力せずに下線を出力しない、またはセルをまとめる。
・投与群と要約統計量は各行でフォーマットを指定して出力。
・文字列は左寄せ、数値は右寄せ(ヘッダーも同じ)。

データ作成・要約統計量算出部分のプログラムは以下になります。
options nocenter linesize=200 nodate nonumber ;
*** Format作成 ;
proc format ;
value GRPF 1 = "Placebo" 2 = "Active" ;
value VISITF 1 = "Week 2" 2 = "Week 4" 3 = "Week 6" ;
run ;
*** テストデータ作成 ;
data TEST ;
do I = 1 to 50 ;
do VISIT = 1 to 3 ;
do GRP = 1 to 2 ;
CHG = -1*VISIT + -0.5*VISIT*GRP + rand("normal") ;
output ;
end ;
end ;
end ;
format GRP GRPF. VISIT VISITF. ;
run ;
*** 要約統計量の算出 ;
proc summary data=TEST n mean stddev nway ;
class VISIT GRP ;
var CHG ;
output out=_OUT(drop=_FREQ_ _TYPE_) n=n mean=mean stddev=sd ;
run ;


レポート作成部分のプログラムは以下になります。
*** PDFへの出力 ;
ods listing close ;
ods pdf startpage=no ;
title ;

*** 1. templateプロシジャ ;
proc template ;
define table xxx ;
style={rules=rows frame=below} ;
header H1-H4 ; *--- 表のタイトル,Summary Statistics,列タイトル ;
define H1 ; text "1. template procedure" ; style={just=l} ; start=VISIT ; end=SD ; end ;
define H2 ; text "Summary Statistics" ; style={just=c} ; start=N ; end=SD ; end ;
define H3 ; text "Visit" ; style={just=l} ; start=VISIT ; end=VISIT ; end ;
define H4 ; text "Treatment" ; style={just=l} ; start=GRP ; end=GRP ; end ;
column VISIT GRP N MEAN SD ; *--- 各変数の定義 ;
define VISIT ;
print_headers = off ;
style = {width=80pt just=l} ;
format = VISITF. ;
blank_dups = on ;
cellstyle GRP = 1 as {borderbottomstyle=none borderbottomwidth=0} ; *--- PDFは効かない... ;
end ;
define GRP ; print_headers=off ; style={width=80pt just=l} ; format=GRPF. ; end ;
define N ; header="N" ; style={width=60pt just=r} ; format=best. ; end ;
define MEAN ; header="Mean" ; style={width=60pt just=r} ; format=8.1 ; end ;
define SD ; header="SD" ; style={width=60pt just=r} ; format=8.2 ; end ;
end ;
run ;
data _null_ ;
set _OUT ;
file print ods=(template="xxx") ;
put _ods_ ;
run ;

*** 2. reportプロシジャ ;
proc report data=_OUT nowd spanrows
style(report)={rules=rows frame=below}
style(header)={just=l} ;
columns ("2. report procedure" VISIT GRP ("Summary Statistics" N MEAN SD)) ;
define VISIT / order "Visit" style={width=80pt just=l} format=VISITF. ;
define GRP / display "Treatment" style={width=80pt just=l} format=GRPF. ;
define N / display "N" style={width=60pt just=r} format=best. ;
define MEAN / display "Mean" style={width=60pt just=r} format=8.1 ;
define SD / display "SD" style={width=60pt just=r} format=8.2 ;
run ;

*** 3. RWI ;
data _null_ ;
set _OUT end=_EOF ;
if _n_ = 1 then do ; *--- Header部分の定義 ;
declare odsout rwi() ; *--- オブジェクトの宣言 ;
rwi.table_start(style_elem: "table", style_attr: "rules=rows frame=below") ; *--- 表の作成 ;
rwi.head_start() ; *--- 表のタイトル ;
rwi.row_start() ;
rwi.format_cell(data: "3. Report Writing Interface (RWI)", style_attr: "just=l", column_span: 5) ;
rwi.row_end() ;
rwi.head_end() ;
rwi.row_start() ; *--- "Summary Statistics"のタイトル出力 ;
rwi.format_cell(data: "", inhibit: "BLR") ;
rwi.format_cell(data: "", inhibit: "BLR") ;
rwi.format_cell(data: "Summary Statistics", inhibit: "LR", column_span: 3, style_attr: "just=c") ;
rwi.row_end() ;
rwi.row_start() ; *--- 列のタイトルと列幅 ;
rwi.format_cell(data: "Visit", inhibit: "LR", style_attr: "cellwidth=80pt just=l") ;
rwi.format_cell(data: "Treatment", inhibit: "LR", style_attr: "cellwidth=80pt just=l") ;
rwi.format_cell(data: "N", inhibit: "LR", style_attr: "cellwidth=60pt just=r") ;
rwi.format_cell(data: "Mean", inhibit: "LR", style_attr: "cellwidth=60pt just=r") ;
rwi.format_cell(data: "SD", inhibit: "LR", style_attr: "cellwidth=60pt just=r") ;
rwi.row_end() ;
end ;
rwi.row_start() ; *--- データ行の定義(データ,フォーマット,罫線,左右寄せ) ;
if GRP = 1 then rwi.format_cell(data: VISIT, format: "VISITF", inhibit: "LRB", style_attr: "just=l") ;
else rwi.format_cell(data: "", inhibit: "LR", style_attr: "just=l") ;
rwi.format_cell(data: GRP, format: "GRPF", inhibit: "LR", style_attr: "just=l") ;
rwi.format_cell(data: N, format: "best", inhibit: "LR", style_attr: "just=r") ;
rwi.format_cell(data: MEAN, format: "8.1", inhibit: "LR", style_attr: "just=r") ;
rwi.format_cell(data: SD, format: "8.2", inhibit: "LR", style_attr: "just=r") ;
rwi.row_end() ;
if _EOF then rwi.table_end() ; *--- 表の作成終了 ;
run ;

ods pdf close ;
ods listing ;


結果は以下になります。
RWI_01.png

まだRWIの詳細を理解していないので直観的な感想になってしまいますが、以下に個人的な見解をまとめておきます。

<総評>
PDF出力に限定し、帳票の細部までカスタマイズを行いたい・拘りたい場合については、RWIは十分に第一選択肢になり得る。

<詳細>
・罫線の制御について、PDF出力では、templateプロシジャやreportプロシジャよりも細かくカスタマイズできる。実際、今回の例でもパーフェクトに要求を満たしているのはRWIのみであった。
・RTFの出力に対応していない点は、実用面から考えるとかなりマイナス。この点は今後の発展に期待するしかない。
・実務的には、「templateプロシジャ+●●」という組み合わせになると思われるが、標準のレイアウトのカスタマイズはRWIも他と比べて遜色ないレベル。
・ODS LAYOUTと同様の機能を持ち、複数帳票のレイアウトもカスタマイズできるため、RWIは様々な機能を1DATAステップ内で実行できる。

まだまだ分からないことだらけですが、何となく、久々に実務で使ってみたいなと思った機能ですので、細々と勉強を続けたいと思います。

Posted on 2015/08/12 Wed. 18:11 [edit]

CM: 0
TB: 0

プロフィール

最新記事

最新コメント

最新トラックバック

月別アーカイブ

カテゴリ

訪れた人

▲Page top

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。