原文載點:http://support.sas.com/resources/papers/proceedings13/131-2013.pdf
SAS雖然可以處理龐大的資料,可是有時候過於龐大的資料沒有辦法用電子郵件寄送,直接放在網路硬碟又很佔空間,上傳下載也花時間,所以能夠壓縮成ZIP檔相信是許多人會做的動作。一般人都是額外安裝winzip, winrar或7zip來額外處理壓縮檔案的事情,但其實在SAS內部整理完資料後就可以直接進行壓縮。以下這篇發表於SAS Global Forum 2013的技術文件就教導了如何用SAS ODS程序來製作ZIP壓縮檔案。
公告
[公告]
2014/01/17
由於已經是faculty的關係,不太有足夠時間寫部落格。因此更新的速度會相當緩慢。再加上近幾年來SAS GLOBAL FORUM沒有出現讓我覺得驚艷的技術文件,所以能分享的文章相對也減少許多。若有人推薦值得分享的SAS技術文件,請利用『問題討論區』告知。
2013/07/19
臉書留言板的功能因為有不明原因故障,因此特此移除。而intensedebate的留言板因管理不易,也一併移除。目前已經開啟內建的 G+ 留言系統,所以請有需要留言的朋友,可直接至『問題討論區』裡面留言。
2013年7月22日 星期一
2011年6月18日 星期六
MORE CUSTOMIZATION?: CREATING SYMBOLS IN RTF FILES USING ODS
原文載點:http://www.lexjansen.com/pharmasug/2004/technicaltechniques/tt12.pdf
有時候想要在 SAS 輸出報表裡面寫一些標題或註解,需要加上一些科學符號、希臘字母、甚至是邏輯運算子等特殊符號時,得使用特別的方法顯示出來。這一篇 2004 年的 PHARMASUG 技術文件可供參考。
有時候想要在 SAS 輸出報表裡面寫一些標題或註解,需要加上一些科學符號、希臘字母、甚至是邏輯運算子等特殊符號時,得使用特別的方法顯示出來。這一篇 2004 年的 PHARMASUG 技術文件可供參考。
2008年11月1日 星期六
Funny ^Stuff~ in My Code – Using ODS ESCAPECHAR
原文載點:http://www2.sas.com/proceedings/forum2007/099-2007.pdf
SAS 的 ODS 系統通常是拿來把報表另存成新的資料或者是列印出比較精緻的格式出來。但大多數的人可能不知道 ODS 還可以像 Word 一樣編輯報表,舉凡加上顏色、字型粗細大小、甚至是上標下標、放特殊符號,通通可以在 ODS 裡面完成。Cynthia L. Zender 於 SAS Global Forum 2007 發表的技術文件教導使用者如何來完成這些動作。
在決定使用 ODS 來編輯文件時,必須先宣告要使用哪種特殊符號來命令 ODS 開始進行一些動作。這個宣告得用 ods escapechar 來完成。比方:
ods escapechar='^';
ods escapechar='~';
ods escapechar='#';
接下來的範例接使用「^」符號來命令 ODS 編輯文件。
範例一:編輯文字
一個很簡單例子。假設要列印出某個字串變數,資料如下所示:
則 ODS 只會印出下面這種相當單調的結果:

下面的程式將可改變字體的粗細、字型和字的顏色:
首先,在原先的 data step 裡面加上紅色部分的程式碼。其中,「^」就是用來宣告之後的 ODS 要進行某些動作。S={} 即是用來編輯。以第一個紅色程式碼來看,^S={font_weight=bold} 接在 quick 前面即是要讓 quick 變成粗體的 quick。第二個紅色程式碼 ^S={foreground=brown} 是將 brown 的顏色變更為棕色的 brown。第三個紅色程式碼 ^S={font_face='Courier New'} 即是變更 fox 的字型為 Courier New 的 fox。所有的動作完成後都必須要在後面加上 ^S={},ODS 才會停止編輯。如果沒有 ^S={} 來中斷,則之前所宣告的編輯動作將會繼續套用在後面的內容中。第四個紅色程式碼比較複雜,這是將前三個紅色程式碼合併。此處將 quick, brown 和 fox 拆成三段,編輯過後用連接符號「||」將結果串起來。但根據我自己試驗的結果,不需要那麼麻煩,直接寫成下列的程式碼也可以做出同樣的效果:
var1 = "The ^S={font_weight=bold}quick ^S={} ^S={foreground=brown}brown ^S={} ^S={font_face='Courier New'}fox ^S={}";
最後,在宣告 ods html 之後,不要忘了加上 ods escapechar='^' 來讓 ODS 知道之前使用的「^」符號是要叫 ODS 做一些編輯動作。
執行後的結果如下所示:

範例二:加上特殊符號
特殊符號的通常用在數學方程式、註解、或化學式裡面。而使用方式也不像編輯文字一樣要用 ^S={options} 來宣告,而只要用 ^={options} 即可。假設想要做出下面這種表格:

則可使用下列程式:
在第一個紅色程式碼中,畢氏定理需要在 a, b, c 各上標一個「2」,這個動作用 ^{super 2} 即可完成。換句話說,super 這個指令在 ^{} 裡面就是拿來做上標用的。第二個紅色程式碼同樣也是要將最後的 1 給上標,所以使用 ^{super 1} 來完成。第三個紅色程式碼同樣也是要加上一個特殊符號當作註解符號。而這個小小的十字架需要使用 ^{dagger} 才能呼叫出來。第四個紅色程式碼是要編輯一個化學方程式,讓一些數字在英文字旁邊坐下標,所以這個動作就得用 ^{sub n} 來完成。接著看最後 proc print 裡面的紅色程式碼。裡面用兩個 title 指令和 footnote 指令來完成表格標題和註解的動作。其中,在 title 裡面,^{thispage} 和 ^{lastpage} 只會作用於 ods rtf 或 ods pdf 裡面。這兩個指令會自動將整份文件的頁數已經該頁是屬於第幾頁列印出來。但這個功能在 ods html 顯示不出來。所以 ^{thispage} 和 ^{lastpage} 在 html 報表裡面會變成空白。同樣地,title2 是讓標題顯示這屬於整份文件的第幾頁,使用 ^{pageof} 來執行。可是這個指令只能在 rtf 文件裡面才會有作用,在 pdf 裡面將會把 ^{pageof} 原封不動地印出來,但在 html 文件裡面則會變成空白。
這是 rtf 文件的結果:

這是 pdf 文件的結果:

範例三:折行
如果一串文字太常,如上例的第四個化學方程式,則可使用折行的指令來讓字串在某處斷行。這個動作只要簡單地在宣告符號後面加上個「n」或「an」(a=任意數字)即可。程式如下:
為了與前兩例做一點區別,此例將宣告符號「^」改成「~」。在 data step 裡面,分別將 The Caffeine molecule is an alkaloid of the methylxanthine family: 和 化學方程式之間各斷一、二、三、四行,因此只要在冒號後面打上「~n」,「~2n」,「~3n」,「~4n」即可。設定完後不要忘了在 proc print 前面加上 ods escapecha='~'; ,否則之前的宣告不會被執行。至於下面很多 title 指令是要展示折行的效果。如果不使用折行,折需要連續呼叫 titlen statement。但有了折行指令,則只需要打一行,裡面再連續使用數個 ~n 即可(如最後的紅色程式碼所示)。僅列出 html 的結果如下:

例四:更改欄位設定
以 ods html 來說,如果沒有特別的設定,則一般的輸出報表會像下圖所示:

如果想要將整行從第一個 Sales 處斷行,並把 Sales Total Sales 改成斜體的話,可使用下列程式碼:
紅色部分就是用來更改那個表格內標籤的設定。^S={font_style=italic} 是用來將後面的 Total Sales 改成斜體字。而緊接著的 ^n 就是用來斷行的。結果如下:

範例五:特殊符號
有些特殊符號需要使用特定的指令來印出。承上例,我們想要在表格後面加上註腳,並打上 trade mark、copy right mark 和美分符號,程式如下:
使用者必須先用一個 _null_ 的 data step,呼叫 %symput 函式把這三個特殊符號叫進來。這三個特殊符號在 SAS 系統裡都有自己的代稱,trade mark 的代碼是 'AE'x,copy right mark 的代碼是 'A9'x,而美分的代碼是 'A2'x。然後用 %put 指令把剛剛用 %symput 叫進來的三個代碼設定為巨集參數,供之後使用。而那些註解可以直接寫在 ods 後面,使用 text 來印出,而所有諸如編輯文字、斷行以及安插特殊符號的指令全部都可以在 text 後面使用。以 ods html 來講, ^S={just=c font_size=18pt} 即是設定整個註腳的字型大小為 18pt,並且全部置中。放在 File 和 Opens 中間的 ^n 即表示從這個位置斷行,最後使用 &hexreg、&hexcopy 和 &hexcent 把 trade mark, copy right mark 和美分符號安插進去。結果如下:

範例六:安插圖片
ODS 也可以拿來安插圖片。先看看程式:
如果只要在 title 上安插圖形的話,則可簡單地於 title statement 後面加上 ^S={preimage="路徑\檔名.jpg"} 來把圖形放上。如果要在文件內容部分的話,得需要先用 proc format 把每一張圖的路徑和檔名分別設定給某個變數的不同的 value,並用一個 $prdimg 來表示(這個字串可以自行設定)。然後在 proc report 裡面的 define 後面放上選項 style(column)={postimage=prdimg.},則每一欄裡面都會安插不同的圖形。若只想單純的更改欄位背景或前景顏色的話,則使用 ^S={backgroun=color1 foreground=color2} 來改變。此例使用 ^S={background=white foreground=black} 把總數欄位的前景顏色改成黑色,背景顏色改成白色。
三種輸出格式的結果如下:

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author:
Cynthia L. Zender
SAS Institute Inc.
Home Office
Las Cruces, NM 88011
Work Phone: (505) 522-3803
Fax: (505) 521-9328
E-mail: Cynthia.Zender@sas.com
SAS 的 ODS 系統通常是拿來把報表另存成新的資料或者是列印出比較精緻的格式出來。但大多數的人可能不知道 ODS 還可以像 Word 一樣編輯報表,舉凡加上顏色、字型粗細大小、甚至是上標下標、放特殊符號,通通可以在 ODS 裡面完成。Cynthia L. Zender 於 SAS Global Forum 2007 發表的技術文件教導使用者如何來完成這些動作。
在決定使用 ODS 來編輯文件時,必須先宣告要使用哪種特殊符號來命令 ODS 開始進行一些動作。這個宣告得用 ods escapechar 來完成。比方:
ods escapechar='^';
ods escapechar='~';
ods escapechar='#';
接下來的範例接使用「^」符號來命令 ODS 編輯文件。
範例一:編輯文字
一個很簡單例子。假設要列印出某個字串變數,資料如下所示:
data use_esc;
length var1 $200;
var1 = "The quick brown fox";
output;
run;
ods html;
proc print data=use_esc;
run;
ods html close;
則 ODS 只會印出下面這種相當單調的結果:

下面的程式將可改變字體的粗細、字型和字的顏色:
data use_esc;
length var1 $200;
var1 = "The quick brown fox";
output;
var1 = "The ^S={font_weight=bold}quick ^S={} brown fox";
output;
var1 = "The quick ^S={foreground=brown}brown ^S={}fox";
output;
var1 = "The quick brown ^S={font_face='Courier New'}fox ^S={}";
output;
var1 = "The ^S={font_weight=bold}quick ^S={}" ||
"^S={foreground=brown}brown ^S={}"||
"^S={font_face='Courier New'}fox ^S={}";
output;
run;
ods html style=sasweb;
ods escapechar='^';
proc print data=use_esc;
run;
ods html close;
首先,在原先的 data step 裡面加上紅色部分的程式碼。其中,「^」就是用來宣告之後的 ODS 要進行某些動作。S={} 即是用來編輯。以第一個紅色程式碼來看,^S={font_weight=bold} 接在 quick 前面即是要讓 quick 變成粗體的 quick。第二個紅色程式碼 ^S={foreground=brown} 是將 brown 的顏色變更為棕色的 brown。第三個紅色程式碼 ^S={font_face='Courier New'} 即是變更 fox 的字型為 Courier New 的 fox。所有的動作完成後都必須要在後面加上 ^S={},ODS 才會停止編輯。如果沒有 ^S={} 來中斷,則之前所宣告的編輯動作將會繼續套用在後面的內容中。第四個紅色程式碼比較複雜,這是將前三個紅色程式碼合併。此處將 quick, brown 和 fox 拆成三段,編輯過後用連接符號「||」將結果串起來。但根據我自己試驗的結果,不需要那麼麻煩,直接寫成下列的程式碼也可以做出同樣的效果:
var1 = "The ^S={font_weight=bold}quick ^S={} ^S={foreground=brown}brown ^S={} ^S={font_face='Courier New'}fox ^S={}";
最後,在宣告 ods html 之後,不要忘了加上 ods escapechar='^' 來讓 ODS 知道之前使用的「^」符號是要叫 ODS 做一些編輯動作。
執行後的結果如下所示:

範例二:加上特殊符號
特殊符號的通常用在數學方程式、註解、或化學式裡面。而使用方式也不像編輯文字一樣要用 ^S={options} 來宣告,而只要用 ^={options} 即可。假設想要做出下面這種表格:

則可使用下列程式:
data sup_sub;
length myvar $200;
myvar = "Pythagorean Theorem: a^{super 2} + b^{super 2} = c^{super 2}";
output;
myvar = "This is something that needs a footnote. ^{super 1}";
output;
myvar = "Macbeth: 'Is this a dagger I see before me?' ^{dagger}";
output;
myvar = "The Caffeine molecule is an alkaloid of the methylxanthine family: " ||
"C^{sub 8}H^{sub 10}N^{sub 4}O^{sub 2}";
output;
run;
ods html file='inline2.html' style=sasweb;
ods rtf file='inline2.rtf' notoc_data;
ods pdf file='inline2.pdf';
ods escapechar='^';
proc print data=sup_sub;
title j=r 'PDF & RTF: Page ^{thispage} of ^{lastpage}';
title2 j=c 'RTF only: ^{pageof}';
footnote '^{super 1}If this were a real footnote, there would be something very academic here.';
footnote2 '^{dagger} Macbeth talked to himself a lot. This quote is from Macbeth: Act 2, Scene 1, Lines 33-39.';
run;
ods _all_ close;
在第一個紅色程式碼中,畢氏定理需要在 a, b, c 各上標一個「2」,這個動作用 ^{super 2} 即可完成。換句話說,super 這個指令在 ^{} 裡面就是拿來做上標用的。第二個紅色程式碼同樣也是要將最後的 1 給上標,所以使用 ^{super 1} 來完成。第三個紅色程式碼同樣也是要加上一個特殊符號當作註解符號。而這個小小的十字架需要使用 ^{dagger} 才能呼叫出來。第四個紅色程式碼是要編輯一個化學方程式,讓一些數字在英文字旁邊坐下標,所以這個動作就得用 ^{sub n} 來完成。接著看最後 proc print 裡面的紅色程式碼。裡面用兩個 title 指令和 footnote 指令來完成表格標題和註解的動作。其中,在 title 裡面,^{thispage} 和 ^{lastpage} 只會作用於 ods rtf 或 ods pdf 裡面。這兩個指令會自動將整份文件的頁數已經該頁是屬於第幾頁列印出來。但這個功能在 ods html 顯示不出來。所以 ^{thispage} 和 ^{lastpage} 在 html 報表裡面會變成空白。同樣地,title2 是讓標題顯示這屬於整份文件的第幾頁,使用 ^{pageof} 來執行。可是這個指令只能在 rtf 文件裡面才會有作用,在 pdf 裡面將會把 ^{pageof} 原封不動地印出來,但在 html 文件裡面則會變成空白。
這是 rtf 文件的結果:

這是 pdf 文件的結果:

範例三:折行
如果一串文字太常,如上例的第四個化學方程式,則可使用折行的指令來讓字串在某處斷行。這個動作只要簡單地在宣告符號後面加上個「n」或「an」(a=任意數字)即可。程式如下:
data linebr;
length myvar $200;
myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: ~n" ||
" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";
output;
myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: ~2n" ||
" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";
output;
myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: ~3n" ||
" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";
output;
myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: ~4n" ||
" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";
output;
run;
ods listing;
ods html file='inline3.html' style=sasweb;
ods rtf file='inline3.rtf' notoc_data;
ods pdf file='inline3.pdf';
ods escapechar='~';
proc print data=linebr;
title 'Using the ODS ESCAPECHAR for line break';
title2 'Title 2';
title3 'Title 3';
title4 'Title 4';
title5 'Title 5';
title6 'Title 6';
title7 'Title 7';
title8 'Title 8';
title9 'Title 9';
title10 'Title 10 ~n Title 11 ~n Title 12 ~n Title 13 ~n Title 14';
run;
ods _all_ close;
為了與前兩例做一點區別,此例將宣告符號「^」改成「~」。在 data step 裡面,分別將 The Caffeine molecule is an alkaloid of the methylxanthine family: 和 化學方程式之間各斷一、二、三、四行,因此只要在冒號後面打上「~n」,「~2n」,「~3n」,「~4n」即可。設定完後不要忘了在 proc print 前面加上 ods escapecha='~'; ,否則之前的宣告不會被執行。至於下面很多 title 指令是要展示折行的效果。如果不使用折行,折需要連續呼叫 titlen statement。但有了折行指令,則只需要打一行,裡面再連續使用數個 ~n 即可(如最後的紅色程式碼所示)。僅列出 html 的結果如下:

例四:更改欄位設定
以 ods html 來說,如果沒有特別的設定,則一般的輸出報表會像下圖所示:

如果想要將整行從第一個 Sales 處斷行,並把 Sales Total Sales 改成斜體的話,可使用下列程式碼:
ods html style=sasweb;
ods escapechar='^';
proc means data=sashelp.shoes sum min mean max;
class Region;
var Sales;
label Sales='^S={font_style=italic}^nShoe Sales';
run;
ods html close;
紅色部分就是用來更改那個表格內標籤的設定。^S={font_style=italic} 是用來將後面的 Total Sales 改成斜體字。而緊接著的 ^n 就是用來斷行的。結果如下:

範例五:特殊符號
有些特殊符號需要使用特定的指令來印出。承上例,我們想要在表格後面加上註腳,並打上 trade mark、copy right mark 和美分符號,程式如下:
data _null_;
hexcode = 'AE'x;
call symput ('hexreg',hexcode);
hexcode1 = 'A9'x;
call symput('hexcopy' , hexcode1);
hexcode2 = 'A2'x;
call symput('hexcent', hexcode2);
run;
** Display the hex codes in the SAS log;
%put hexreg= &hexreg;
%put hexcopy= &hexcopy;
%put hexcent= &hexcent;
ods html file='inline5.html' style=sasweb;
ods rtf file='inline5.rtf' notoc_data startpage=no;
ods pdf file='inline5.pdf' startpage=no;
ods escapechar='^';
ods noptitle;
proc means data=sashelp.shoes sum min mean max;
class Region;
var Sales;
label Sales='^S={font_style=italic}^nShoe Sales';
run;
ods pdf text="^S={just=c font_size=18pt}PDF File^nOpens with Adobe Reader^n
&hexreg &hexcopy My 2&hexcent";
ods rtf text="^S={just=c font_size=18pt}RTF File^nOpens with Microsoft Word^n
&hexreg &hexcopy My 2&hexcent";
ods html text="^S={just=c font_size=18pt}HTML File^nOpens with Microsoft Internet
Explorer^n &hexreg &hexcopy My 2&hexcent";
proc freq data=sashelp.shoes;
tables Product /nocum;
label Product='^S={font_style=italic}Shoe Types Sold';
run;
ods _all_ close;
使用者必須先用一個 _null_ 的 data step,呼叫 %symput 函式把這三個特殊符號叫進來。這三個特殊符號在 SAS 系統裡都有自己的代稱,trade mark 的代碼是 'AE'x,copy right mark 的代碼是 'A9'x,而美分的代碼是 'A2'x。然後用 %put 指令把剛剛用 %symput 叫進來的三個代碼設定為巨集參數,供之後使用。而那些註解可以直接寫在 ods 後面,使用 text 來印出,而所有諸如編輯文字、斷行以及安插特殊符號的指令全部都可以在 text 後面使用。以 ods html 來講, ^S={just=c font_size=18pt} 即是設定整個註腳的字型大小為 18pt,並且全部置中。放在 File 和 Opens 中間的 ^n 即表示從這個位置斷行,最後使用 &hexreg、&hexcopy 和 &hexcent 把 trade mark, copy right mark 和美分符號安插進去。結果如下:

範例六:安插圖片
ODS 也可以拿來安插圖片。先看看程式:
proc format;
value $prdimg 'Boot' = 'c:\temp\boot.jpg'
"Women's Dress" = 'c:\temp\dressheels.jpg'
'Slipper' = 'c:\temp\slipper.jpg';
run;
ods html file='inline6.html' style=sasweb;
ods rtf file='inline6.rtf' notoc_data;
ods pdf file='inline6.pdf';
ods escapechar='^';
proc report data=sashelp.shoes nowd style(column) = {vjust=b};
title '^S={preimage="c:\temp\shoe_logo.jpg"}';
where product in ('Boot', 'Slipper', "Women's Dress");
column Product Sales N;
define Product / group
style(header)={background=white foreground=black}
style(column)={postimage=$prdimg.};
define Sales / sum;
define N / '^S={background=white foreground=black}Number of Sales';
run;
ods _all_ close;
如果只要在 title 上安插圖形的話,則可簡單地於 title statement 後面加上 ^S={preimage="路徑\檔名.jpg"} 來把圖形放上。如果要在文件內容部分的話,得需要先用 proc format 把每一張圖的路徑和檔名分別設定給某個變數的不同的 value,並用一個 $prdimg 來表示(這個字串可以自行設定)。然後在 proc report 裡面的 define 後面放上選項 style(column)={postimage=prdimg.},則每一欄裡面都會安插不同的圖形。若只想單純的更改欄位背景或前景顏色的話,則使用 ^S={backgroun=color1 foreground=color2} 來改變。此例使用 ^S={background=white foreground=black} 把總數欄位的前景顏色改成黑色,背景顏色改成白色。
三種輸出格式的結果如下:

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author:
Cynthia L. Zender
SAS Institute Inc.
Home Office
Las Cruces, NM 88011
Work Phone: (505) 522-3803
Fax: (505) 521-9328
E-mail: Cynthia.Zender@sas.com
2008年8月23日 星期六
Using 22 Easy Tricks with ODS to Generate Colorful Reports
原文載點:http://www.lexjansen.com/mwsug/2007/Tutorials/T10-2007.pdf
ODS 系統在 SAS V9.1 版中已經逐漸發揮他的威力,到了 V9.2 版後更是往上提升了一個階層。不過很多人以為用用 ODS 把圖或報表直接輸出就已經是最方便的,殊不知他可以結合最簡單的 PROC PRINT 程序將輸出結果強化。這一篇在 NESUG 2007 發表的技術文件詳細記載了如何讓 ODS 搭配 PROC PRINT 來產生更美觀的報表,也同時揭露了一些在 SAS 手冊裡都沒有介紹的指令。
簡單來講,如果要用 PROC PRINT 程序加上 ODS 來列印報表,在完全沒有額外設定,只使用預設值的情況下,語法大概就諸如此款:

然後得到的結果是:

如果你覺得上面這種呈現方式有點像是墓碑上刻出來的文字,而想要換成別的樣式或顏色,那麼就得靠 PROC PRINT 程序手冊裡面都很少提到(至少 SAS online documentation 沒有寫)的 style option!
style option 基本的撰寫格式如下:

以這個圖例說明:

利用四個 style 指令將 Obs 標題顏色、表格內資料背景顏色、Obs 列顏色以及底部 total 底色一次進行修改。
接下來又一步一步來介紹不同 style 指令的用法。
1. 更改標題列顏色
如果想要將標題列著成黃色,如下圖所示:

則可以用下面這道程式來實現:

其中,黃色標記處 style(header)={background=yellow}; 即是讓標題列變成黃色的關鍵。
2. 更改總和列顏色和字型和大小
PROC PRINT 裡面有個 SUM statement 可以計算每個欄位的總和,如想要更改此處的背景顏色、字型樣式和字型大小,如下圖所示:

則可以使用這道程式:

黃色標明處 style (grandtotal)={background=grayee font=(Arial) font_size=6}; 即是更改由橘色標明處 SUM statement 所算出來的兩個總和欄位的背景顏色(grayee)、字型(Arial)和字型大小(font_size)。如果沒有 SUM statement,則黃色標明處的語法將不會有任何作用。
3. 更改表格資料欄背景顏色
如想要改變表格資料的背景顏色,如下圖所示:

則語法如下:

黃色標明處 style(data)={background=grayee} 即是用來設定資料欄位背景顏色。附帶一提,標題列會自動斷成兩行是利用紅色標明處的 split='*' 進行設定,然後在橘色標明處 label statement 裡面將標題要斷行的地方打上 * 即可。
4. 更改分類總和欄位背景顏色
如果有使用 by statement 來計算不同分類欄位的總和,則其背景顏色也可以修改,如下圖所示:

語法如下:


此程式由於有使用 by origcity; 和 sum statement 來計算每個程式 sales2005 和 sales2006 的總和,所以要修改分類總和欄位的背景顏色,就得用黃色標明處的 style(total)={background=light green}; 來設定。
5. 更改特定欄位字體顏色
若想指定某個欄位的字型顏色,如下圖所示:

可使用下列程式:


黃色標明處的 var month 後面加上 /style={foreground=red}; 就可以更改 month 這個欄位字型顏色。此外,一開頭的 SAS logo 是用 title3 後面的 "^S=preimage='c:\ben\qp\SAS_logo.bmp'}" 所貼上。
總結:作者有坦承這篇文件沒有把 22 個 trick 都用上,不過會在 conference 裡面說明。不過由於沒有她在會議裡面的任何影音檔,所以無法得知其他沒有在文件裡面的小技巧是什麼。但上述這些語法已經足夠讓表格變的更漂亮,因此有興趣的人可以玩玩不同組合最出現什麼情況。
CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Ben Cochran
The Bedford Group
Raleigh, NC 27607
Office: 919.831.1191
Fax: 919.831.1191
Email: bedfordgroup@nc.rr.com
Web: www.bedford-group.com
ODS 系統在 SAS V9.1 版中已經逐漸發揮他的威力,到了 V9.2 版後更是往上提升了一個階層。不過很多人以為用用 ODS 把圖或報表直接輸出就已經是最方便的,殊不知他可以結合最簡單的 PROC PRINT 程序將輸出結果強化。這一篇在 NESUG 2007 發表的技術文件詳細記載了如何讓 ODS 搭配 PROC PRINT 來產生更美觀的報表,也同時揭露了一些在 SAS 手冊裡都沒有介紹的指令。
簡單來講,如果要用 PROC PRINT 程序加上 ODS 來列印報表,在完全沒有額外設定,只使用預設值的情況下,語法大概就諸如此款:

然後得到的結果是:

如果你覺得上面這種呈現方式有點像是墓碑上刻出來的文字,而想要換成別的樣式或顏色,那麼就得靠 PROC PRINT 程序手冊裡面都很少提到(至少 SAS online documentation 沒有寫)的 style option!
style option 基本的撰寫格式如下:

以這個圖例說明:

利用四個 style 指令將 Obs 標題顏色、表格內資料背景顏色、Obs 列顏色以及底部 total 底色一次進行修改。
接下來又一步一步來介紹不同 style 指令的用法。
1. 更改標題列顏色
如果想要將標題列著成黃色,如下圖所示:

則可以用下面這道程式來實現:

其中,黃色標記處 style(header)={background=yellow}; 即是讓標題列變成黃色的關鍵。
2. 更改總和列顏色和字型和大小
PROC PRINT 裡面有個 SUM statement 可以計算每個欄位的總和,如想要更改此處的背景顏色、字型樣式和字型大小,如下圖所示:

則可以使用這道程式:

黃色標明處 style (grandtotal)={background=grayee font=(Arial) font_size=6}; 即是更改由橘色標明處 SUM statement 所算出來的兩個總和欄位的背景顏色(grayee)、字型(Arial)和字型大小(font_size)。如果沒有 SUM statement,則黃色標明處的語法將不會有任何作用。
3. 更改表格資料欄背景顏色
如想要改變表格資料的背景顏色,如下圖所示:

則語法如下:

黃色標明處 style(data)={background=grayee} 即是用來設定資料欄位背景顏色。附帶一提,標題列會自動斷成兩行是利用紅色標明處的 split='*' 進行設定,然後在橘色標明處 label statement 裡面將標題要斷行的地方打上 * 即可。
4. 更改分類總和欄位背景顏色
如果有使用 by statement 來計算不同分類欄位的總和,則其背景顏色也可以修改,如下圖所示:

語法如下:


此程式由於有使用 by origcity; 和 sum statement 來計算每個程式 sales2005 和 sales2006 的總和,所以要修改分類總和欄位的背景顏色,就得用黃色標明處的 style(total)={background=light green}; 來設定。
5. 更改特定欄位字體顏色
若想指定某個欄位的字型顏色,如下圖所示:

可使用下列程式:


黃色標明處的 var month 後面加上 /style={foreground=red}; 就可以更改 month 這個欄位字型顏色。此外,一開頭的 SAS logo 是用 title3 後面的 "^S=preimage='c:\ben\qp\SAS_logo.bmp'}" 所貼上。
總結:作者有坦承這篇文件沒有把 22 個 trick 都用上,不過會在 conference 裡面說明。不過由於沒有她在會議裡面的任何影音檔,所以無法得知其他沒有在文件裡面的小技巧是什麼。但上述這些語法已經足夠讓表格變的更漂亮,因此有興趣的人可以玩玩不同組合最出現什麼情況。
CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Ben Cochran
The Bedford Group
Raleigh, NC 27607
Office: 919.831.1191
Fax: 919.831.1191
Email: bedfordgroup@nc.rr.com
Web: www.bedford-group.com
2008年2月1日 星期五
Customizing Output for Regression Analyses Using ODS and DATA Step
原文載點:http://www.nesug.info/Proceedings/nesug07/po/po22.pdf
在配飾模式時,SAS 功力比較好的人可能會用 ODS 把輸出報表弄得好看一點。不過有人覺得好還要更好,比方說能夠把不同等級的 p-value 標上不同的顏色,或者是把表格欄位名稱弄成粗體字等等。Zhenyi Xue 在 NESUG 2007 發表了數個 macro 讓使用者能夠把 linear regression model、logistic regression model 和 Cox PH model 的輸出報表弄得更漂亮。
LINEAR REGRESSION
此處有三個 macro 可以用,分別是:
第一個和第二個程式是分別拿來配飾 simple linear regression model 和 multiple linear regression model。使用者只要把 response variable 和 predictor variable 分別設定在 Response 和 X0 這兩個巨集參數裡面即可。這兩個程式將一些基本需要拿來製作報表的數據另存成新的資料集,然後第三個程式會在叫出這些資料集來繪製表格。等到執行第三個程式時,會自動去呼叫前面這兩個程式來輸出資料。裡面有四個巨集參數:
1. Dat:指定資料集檔名。
2. Response:指定 response variable。
3. X0:指定independent variable。
4. Type:指定要跑 simple linear regression 還是 multiple linear regression。如果是前者,則請輸入「Uni」,如果是後者,則請輸入「Multi」。
以下是兩個範例:
第一個範例是針對每一個不同的 independent variable 去配飾不同的 simple linear regression model,因此總共會有七個結果,然後 %sum_glm 再把這七個結果合併成一個報表,如下所示:

第二個範例則是配飾一個 multiple linear regression model。結果如下所示:

根據原始程式碼內的設定,p-value 小於 0.01 的值都會被標記成紅色。0.01 到 0.05 則標記成澄色,0.05 到 0.2 則標記成綠色,大於 0.2 則就維持黑色。如果想要改變顏色或這是 p-value 的顏色區分點,則可以去改第三個程式內標記成紅色的那個區塊(也就是 PROC FORMAT 那一行)。
LOGISTIC REGRESSION
Logistic regression model 同樣也有三個 macro:
用法幾乎是和前面的 %sum_glm 一模一樣,連巨集參數的名稱和用法也都一模一樣。直接來看範例:
與之前的 %sum_glm 比較起來沒有任何差別。做出來的報表也很相似:

同樣地,如果想要變動 p-value 的顏色,請到 %sum_logistic 裡面的紅色 PROC FORMAT 部分進行修改。
COX REGRESSION (PROPORTIONAL HAZARDS MODEL)
此處也是有三個巨集程式:
用法也是一樣:
結果也是一樣:

希望這些程式能夠對大家有所幫助。
CONTACT INFORMATION
Your comments and questions are valued and encouraged. If you want an electronic copy of the macros, please contact the author at:
Zhenyi Xue
Cardiovascular Research Institute
Washington Hospital Center
MedStar Health, Inc.
110 Irving Street NW, Suite 6D
Washington, DC 20010
Work Phone: 202-877-2987
Fax: 202-877-9337
Email: Zhenyi.Xue@MedStar.net
在配飾模式時,SAS 功力比較好的人可能會用 ODS 把輸出報表弄得好看一點。不過有人覺得好還要更好,比方說能夠把不同等級的 p-value 標上不同的顏色,或者是把表格欄位名稱弄成粗體字等等。Zhenyi Xue 在 NESUG 2007 發表了數個 macro 讓使用者能夠把 linear regression model、logistic regression model 和 Cox PH model 的輸出報表弄得更漂亮。
LINEAR REGRESSION
此處有三個 macro 可以用,分別是:
/*******************************************
*Univariate Linear Regression with PROC GLM*
*******************************************/
%Macro GLMMacro_Uni(X0);
*Use ODS in GLM procedure to generate datasets containing model fitting statistics;
proc glm data=&Dat;
model &Response =&X0 /solution;
ods output ParameterEstimates=dPara;
ods output NObs=dNum;
ods output FitStatistics=dRsq;
quit;
*Use DATA steps to generate final dataset dGLMAll for future output;
data dNum2; set dNum(rename=(NObsUsed=N_of_Obs)); if _N_=1 then delete;
length _Variable $25.; _Variable="&X0"; keep _Variable N_of_Obs;
data dPara2; set dPara; if _N_=1 then delete;
length _Variable $25.; _Variable=Parameter; drop Dependent tValue Parameter;
data dRsq2; set dRsq;
length _Variable $25.; _Variable="&X0"; keep _Variable RSquare;
run;
proc sort data=dRsq2; by _Variable;
proc sort data=dPara2; by _Variable;
proc sort data=dNum2; by _Variable;
data dPara3; merge dPara2 dRsq2 dNum2; by _Variable; run;
data dGLMAll; set dGLMAll dPara3(rename=(Probt=P_Value));
CI_lower = estimate - 1.96 * stderr;
CI_upper = estimate + 1.96 * stderr;
Variable=_Variable;
run;
%mend GLMMacro_Uni;
/*********************************************
*Multivariate Linear Regression with PROC GLM*
*********************************************/
%Macro GLMMacro(X0);
*Use ODS in GLM procedure to generate datasets containing model fitting statistics;
proc glm data=&Dat;
model &Response =&X0 /solution;
ods output ParameterEstimates=dPara;
ods output NObs=dNum;
ods output FitStatistics=dRsq;
quit;
*Use DATA steps to generate final dataset dGLMAll for future output;
data dNum2; set dNum(rename=(NObsUsed=N_of_Obs));
if _N_=1 then delete; keep N_of_Obs;
data dRsq2; set dRsq; keep RSquare;
data dNumR; merge dNum2 dRsq2;
data dPara2; set dPara(rename=(Parameter=Variable Probt=P_Value));
if _N_=1 then delete;
CI_lower = estimate - 1.96 * stderr;
CI_upper = estimate + 1.96 * stderr;
drop Dependent tValue;
data dGLMAll; set dPara2 dNumR; run;
%mend GLMMacro;
/*********************************************
*Generate Output File with ODS and PROC PRINT*
*********************************************/
%macro sum_glm(
Dat=, /*Dataset Name, Exp: work.finaldata*/
Response=, /*Continuous Dependent Variable, Exp: BloodPressure*/
Predictor=, /*List of Independent Variables, Exp: Age Male Hx_MI*/
Type= /*Uni- or Multi-variate Analysis, only can enter: Uni or Multi*/);
*FORMAT procedure for traffic lighted p-value output;
proc format; value pf 0-0.01="red" 0.01-0.05="orange" 0.05-0.2="green" other="";
options nocenter nodate nonumber missing=' ';
data dGLMAll; set _NULL_; run;
*Use DO-WHILE loop to separate the predictor variables and invoke the GLMMacro;
%let I=0;
%do %while (%scan(&Predictor, &I+1, %str( )) ne %str( ));
%let I=%eval(&I+1);
%end;
%if &Type=Uni %then %do;
%do Z=1 %to &I;
%GLMMacro_Uni(%scan(&Predictor, &Z, %str( )))
%end;
%end;
%if &Type=Multi %then %do;
%GLMMacro(&Predictor)
%end;
*Use PRINT procedure and ODS to generate the output file;
ods pdf style=journal startpage=no file="&folder..\&Type.variate linear.pdf";
proc print data=dGLMAll split=' ' noobs Style(HEADER) = {font_weight=bold};
label Variable='Variable Name' Estimate='Regression Coefficient'
P_Value='P Value' CI_lower='Lower CI' CI_upper='Upper CI'
N_of_Obs='Sample Size' RSquare='R Square';
var Variable N_of_Obs RSquare Estimate StdErr CI_lower CI_upper;
var P_Value / style={foreground=pf.};
format Estimate StdErr P_Value CI_lower CI_upper 5.3 RSquare 4.2;
title1 "&Type.variate Generalized Linear Model on &Response";
title2 "Data folder=&folder";
title3 'Predictors are either continuous or coded as 0/1 categorical(ref=0)';
run;
ods pdf close;
%mend sum_glm;
第一個和第二個程式是分別拿來配飾 simple linear regression model 和 multiple linear regression model。使用者只要把 response variable 和 predictor variable 分別設定在 Response 和 X0 這兩個巨集參數裡面即可。這兩個程式將一些基本需要拿來製作報表的數據另存成新的資料集,然後第三個程式會在叫出這些資料集來繪製表格。等到執行第三個程式時,會自動去呼叫前面這兩個程式來輸出資料。裡面有四個巨集參數:
1. Dat:指定資料集檔名。
2. Response:指定 response variable。
3. X0:指定independent variable。
4. Type:指定要跑 simple linear regression 還是 multiple linear regression。如果是前者,則請輸入「Uni」,如果是後者,則請輸入「Multi」。
以下是兩個範例:
%sum_glm(dat=nesug07, response=LVEF, predictor=Male Age Hx_MI NumVes Hx_CAD Hx_CRI Hypertension, Type=Uni) ;
%sum_glm(dat=nesug07, response=LVEF, predictor=Male Age Hx_MI NumVes Hx_CAD Hx_CRI Hypertension, Type=Multi) ;
第一個範例是針對每一個不同的 independent variable 去配飾不同的 simple linear regression model,因此總共會有七個結果,然後 %sum_glm 再把這七個結果合併成一個報表,如下所示:

第二個範例則是配飾一個 multiple linear regression model。結果如下所示:

根據原始程式碼內的設定,p-value 小於 0.01 的值都會被標記成紅色。0.01 到 0.05 則標記成澄色,0.05 到 0.2 則標記成綠色,大於 0.2 則就維持黑色。如果想要改變顏色或這是 p-value 的顏色區分點,則可以去改第三個程式內標記成紅色的那個區塊(也就是 PROC FORMAT 那一行)。
LOGISTIC REGRESSION
Logistic regression model 同樣也有三個 macro:
/**************************************************
*Univariate Logistic Regression with PROC LOGISTIC*
**************************************************/
%Macro LogisMacro_Uni(X0)/store;
*Use ODS in LOGISTIC procedure to generate new datasets which contain model fitting
statistics;
proc logistic descending data=&Dat;
model &Response =&X0/ CLODDS=Wald;
ods output ParameterEstimates=dPara;
ods output CLOddsWald=dCIWald;
ods output Nobs=dNum;
ods output ResponseProfile=dEvent;
quit;
*Use DATA steps to generate final dataset dLogisAll for future output;
data dNum2; set dNum; if _N_ = 2;
length _Variable $25.;
N_of_Obs=N; _Variable="&X0"; keep _Variable N_of_Obs;
data dEvent2; set dEvent; if _N_ = 1;
length _Variable $25.;
N_of_Events=Count; _Variable="&X0"; keep _Variable N_of_Events;
data dPara2; set dPara; if _N_=1 then delete;
length _Variable $25.; _Variable=Variable;
drop DF WaldChisq Variable;
data dCIWald2; set dCIWald;
length _Variable $25.; _Variable=Effect;
drop Unit Effect;
run;
proc sort data=dCIWald2; by _Variable;
proc sort data=dPara2; by _Variable;
proc sort data=dNum2; by _Variable;
proc sort data=dEvent2; by _Variable;
data dPara3; merge dPara2 dCIWald2 dNum2 dEvent2; by _Variable;
data dLogisAll; set dLogisAll dPara3; Variable=_Variable; run;
%mend LogisMacro_Uni;
/****************************************************
*Multivariate Logistic Regression with PROC LOGISTIC*
****************************************************/
%Macro LogisMacro(X0);
*Use ODS in LOGISTIC procedure to generate new datasets which contain model fitting
statistics;
proc logistic descending data=&Dat;
model &Response =&X0/ CLODDS=Wald;
ods output ParameterEstimates=dPara;
ods output CLOddsWald=dCIWald;
ods output Nobs=dNum;
ods output ResponseProfile=dEvent;
quit;
*Use DATA steps to generate final dataset dLogisAll for future output;
data dPara2; set dPara; if _N_=1 then delete; drop DF WaldChisq;
data dNum2; set dNum; if _N_ = 2; N_of_Obs=N; keep N_of_Obs;
data dEvent2; set dEvent; if _N_ = 1; N_of_Events=Count; keep N_of_Events;
data dNumEvn; merge dNum2 dEvent2;
data dCIWald2; set dCIWald(rename=(Effect=Variable)); drop Unit;
run;
proc sort data=dCIWald2; by Variable;
proc sort data=dPara2; by Variable;
data dPara3; merge dPara2 dCIWald2; by Variable;run;
data dLogisAll; set dPara3 dNumEvn; run;
%mend LogisMacro;
/*********************************************
*Generate Output File with ODS and PROC PRINT*
*********************************************/
%macro sum_logistic(
Dat=, /*Dataset Name, Exp: work.nesug07*/
Response=, /*Dependent Variable, Exp: Death*/
Predictor=,/*List of Independent Variables, Exp: Age Male Hx_MI*/
Type= /*Uni- or Multi-variate Analysis, only can enter: Uni or Multi*/);
*FORMAT procedure for traffic lighted p-value output;
proc format; value pf 0-0.01="red" 0.01-0.05="orange" 0.05-0.2="green" other="";
options nocenter nodate nonumber missing=' ';
data dLogisAll; set _NULL_; run;
*Use DO-WHILE loop to separate the predictor variables and invoke the LogisMacro;
%let I=0;
%do %while (%scan(&Predictor, &I+1, %str( )) ne %str( ));
%let I=%eval(&I+1);
%end;
%if &Type=Uni %then %do;
%do Z=1 %to &I; %LogisMacro_Uni(%scan(&Predictor, &Z, %str( ))) %end;
%end;
%if &Type=Multi %then %do;
%LogisMacro(&Predictor)
%end;
*Use PRINT procedure and ODS to generate the output file;
ods pdf style=journal startpage=no file="&folder..\&Type.variate logistic.pdf";
proc print data=dLogisAll split=' ' noobs Style(HEADER) = {font_weight=bold};
label Variable='Variable Name' Estimate='Regression Coefficient' ProbChiSq='P
Value' LowerCL='Lower OR' UpperCL='Upper OR' N_of_Obs='Sample Size'
N_of_Events='No. Events';
var Variable N_of_Obs N_of_Events Estimate StdErr;
var ProbChisq / style={foreground=pf.};
var OddsRatioEst LowerCL UpperCL ;
format Estimate StdErr ProbChisq 5.3 OddsRatioEst LowerCL UpperCL 4.2;
title1 "&Type.variate Logistic Model on &Response. (1)";
title2 "Data folder=&folder";
title3 'Predictors are either continuous or coded as 0/1 categorical(ref=0)';
run;
ods pdf close;
%mend sum_logistic;
用法幾乎是和前面的 %sum_glm 一模一樣,連巨集參數的名稱和用法也都一模一樣。直接來看範例:
%sum_logistic(dat=nesug07, response=TVR_MACE,
predictor=Male Age Hx_MI NumVes Hx_CAD Hx_CRI Hypertension LVEF, Type=Uni);
%sum_logistic(dat=nesug07, response=TVR_MACE,
predictor=Male Age Hx_MI NumVes Hx_CAD Hx_CRI Hypertension LVEF, Type=Multi);
與之前的 %sum_glm 比較起來沒有任何差別。做出來的報表也很相似:

同樣地,如果想要變動 p-value 的顏色,請到 %sum_logistic 裡面的紅色 PROC FORMAT 部分進行修改。
COX REGRESSION (PROPORTIONAL HAZARDS MODEL)
此處也是有三個巨集程式:
%Macro CoxMacro_Uni(X0);
*Use ODS in PHREG procedure to generate datasets for model fitting statistics;
proc phreg data=&Dat;
model &Time * &Status(0) =&X0/ RL;
assess var=(&X0) PH/resample;
ods output ParameterEstimates=dPara;
ods output CensoredSummary=dCens;
ods output ProportionalHazardsSupTest=dPH;
quit;
*Use DATA steps to generate final dataset dCoxAll for future output;
data dCens2; set dCens;
length _Variable $25.; _Variable="&X0"; keep _Variable Total Event PctCens;
data dPara2; set dPara;
length _Variable $25.; _Variable=Variable; drop Variable;
data dPH2; set dPH;
length _Variable $25.; _Variable=Variable; drop Variable;
run;
proc sort data=dPara2; by _Variable;
proc sort data=dCens2; by _Variable;
proc sort data=dPH2; by _Variable;
data dPara3; merge dPara2(rename=(ProbChisq=p_value HazardRatio=HR))
dCens2 dPH2(rename=(pvalue=STPHA_p));
by _Variable;
drop DF Chisq MaxAbsValue Replications Seed;
data dCoxAll; set dCoxAll dPara2; Variable=_Variable; run;
%mend CoxMacro_Uni;
/********************************************
*Multivariate Cox Regression with PROC PHREG*
********************************************/
%Macro CoxMacro(X0);
*Use ODS in PHREG procedure to generate datasets for model fitting statistics;
proc phreg data=&Dat;
model &Time * &Status(0) =&X0/ RL;
ods output ParameterEstimates=dPara;
ods output CensoredSummary=dCens;
quit;
*Use DATA steps to generate final dataset dCoxAll for future output;
data dCens2; set dCens; keep Total Event PctCens;
data dPara2; set dPara(rename=(ProbChisq=p_value HazardRatio=HR) drop=(DF Chisq));
data dCoxAll; set dPara2 dCens2; run;
%mend CoxMacro;
/*********************************************
*Generate Output File with ODS and PROC PRINT*
*********************************************/
%macro sum_cox(
Dat=, /*Dataset Name, Exp: work.nesug07*/
Status=, /*Variable for Censoring Status(0 is censoring), Exp: Death*/
Time=, /*Time to Event Variable, Exp: FU_Month*/
Predictor=,/*List of Independent Variables, Exp: Age Male Hx_MI*/
Type= /*Uni- or Multi-variate Analysis, only can enter: Uni or Multi*/);
*FORMAT procedure for traffic lighted p-value output;
proc format; value pf 0-0.01="red" 0.01-0.05="orange" 0.05-0.2="green" other="";
options nocenter nodate nonumber missing=' ';
data dCoxAll; set _NULL_; run;
*Use DO-WHILE loop to separate the predictor variables;
%let I=0;
%do %while (%scan(&Predictor, &I+1, %str( )) ne %str( ));
%let I=%eval(&I+1);
%end;
*Invoke CoxMacro for univariate analysis, use PRINT procedure and ODS to generate
the output file;
%if &Type=Uni %then %do;
%do Z=1 %to &I; %CoxMacro_Uni(%scan(&Predictor, &Z, %str( ))) %end;
ods pdf style=journal startpage=no file="&folder..\&Type.variate cox.pdf";
proc print data=dCoxAll split=' ' noobs Style(HEADER) = {font_weight=bold};
label Variable='Variable Name' Estimate='Regression Coefficient'
p_value='P Value' HRLowerCL='Lower HR' HRUpperCL='Upper HR'
STPHA_p='PH Assumption';
var Variable Label Estimate StdErr;
var p_value / style={foreground=pf.};
var HR HRLowerCL HRUpperCL Event Total;
var STPHA_p / style={foregroun f.}; d=p
format HR HRLowerCL HRUpperCL 3.1 Estimate StdErr p_value STPHA_p 5.3;
title1 "Univariate Cox Model(Propotional Hazard Model) on &Status.(1)";
title2 "Data folder=&folder";
title3 'Predictors are either continuous or coded as 0/1 categorical(ref=0)';
run;
ods pdf close;
%end;
*Invoke CoxMacro for multivariate analysis, use PRINT procedure and ODS to generate
the output file;
%if &Type=Multi %then %do;
%CoxMacro(&Predictor)
ods pdf style=journal startpage=no file="&folder..\&Type.variate cox.pdf";
proc print data=dCoxAll split=' ' noobs Style(HEADER) = {font_weight=bold};
label Variable='Variable Name' Estimate='Regression Coefficient'
p_value='P Value' HRLowerCL='Lower HR' HRUpperCL='Upper HR';
var Variable Label Estimate StdErr;
var p_value / style={foreground=pf.};
var HR HRLowerCL HRUpperCL Event Total;
format HR HRLowerCL HRUpperCL 3.1 Estimate StdErr p_value 5.3;
title1 "Multivariate Cox Model(Propotional Hazard Model) on &Status. (1)";
title2 "Data folder=&folder";
title3 'Predictors are either continuous or coded as 0/1 categorical(ref=0)';
run;
ods rtf close;
%end;
%mend sum_cox;
用法也是一樣:
%sum_cox(dat=nesug07, status=TVR_MACE, time=TVR_MACE_Days,
predictor=Male Age Hx_MI NumVes Hx_CAD Hx_CRI Hypertension LVEF, Type=Uni) ;
%sum_cox(dat=nesug07, status=TVR_MACE, time=TVR_MACE_Days,
predictor=Male Age Hx_MI NumVes Hx_CAD Hx_CRI Hypertension LVEF, Type=Multi) ;
結果也是一樣:

希望這些程式能夠對大家有所幫助。
CONTACT INFORMATION
Your comments and questions are valued and encouraged. If you want an electronic copy of the macros, please contact the author at:
Zhenyi Xue
Cardiovascular Research Institute
Washington Hospital Center
MedStar Health, Inc.
110 Irving Street NW, Suite 6D
Washington, DC 20010
Work Phone: 202-877-2987
Fax: 202-877-9337
Email: Zhenyi.Xue@MedStar.net
2007年6月11日 星期一
Saving Trees with Output Delivery System (ODS)
原文載點:http://www2.sas.com/proceedings/forum2007/057-2007.pdf
一般人在配適模式的時候,可能由於變數很多,所以整個報表落落長。大家比較會注重最後的參數估計表,笨方法就是找到那個表格然後剪下來貼在其他的文書處理軟體中,聰明的人會用 ODS 把那個表格單獨存成 rtf 檔。但如果要配適的模式很多,要用到很多 procedure,最好還是用一些 macro 來解決冗長的程式碼。Angelina D. Tan, Nancy Dilehl, Jay N. Mandrekar 在 SAS Global Forum 2007 (SUGI 今年把名稱改成 SAS Global Forum了)中發表了三個「懶人 macro 包」,讓懶得寫那麼多 SAS code 的人能夠輕鬆配適模式,並且用 ODS 和 proc report 把參數估計表美美的存出來。
Regression model
macro 程式如下:
這個 macro 包含五個參數:
此範例是使用在 tana 這個 library 裡面的 fitness 資料檔。自變數是 Age、Weight、RunTime、RunPulse、RestPulse 和 MaxPulse 共計六個。依變數是 Oxygen,而參數估計表則另存到 preg 這個資料檔裡面。
然後便可以用下面這個 prog report 指令把參數估計表很完美地打印在 preg.doc 這個檔案裡面。我建議使用者不用太需要理會裡面的設定,只要記得把 ods rtf 後面的設定改成你要的路徑和檔名即可。當然如果你想要用別的 title 的話也可以把 title1 後面那串字改掉。不過基本上其他的程式碼都不需要變動。

如果你覺得這種兩階段的程式還是太麻煩,可以把上面的 proc report 程序丟進 pReg 裡面,但必須把 ods rtf 那行改成 macro 變數: ods rtf file="&filename"; 並將 macro 程式第一行改成: %macro pReg (dsn=, varlist=, numvars=, respvar=, outdsn=table, filename);
Logistic regression model
macro 程式如下:
同樣有五個參數,定義完全和 pReg 雷同。在此不多加描述。
使用範例如下:
然後用 proc report 列印參數估計表:
這個打印出來的參數估計表比較炫,會把顯著的參數用高亮度的黃色標記出來。

Cox PH model
macro 程式如下:
這個 macro 使用到的參數有七個:
最後還是要用 ODS 和 proc report 把參數估計表存出來:

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Angelina Tan
Mayo Clinic, Division of Biostatistics
200 First Street SW
Rochester MN 55905
Phone: 507-284 5743
Fax: 507-266 2477
Email: tan.angelina@mayo.edu
一般人在配適模式的時候,可能由於變數很多,所以整個報表落落長。大家比較會注重最後的參數估計表,笨方法就是找到那個表格然後剪下來貼在其他的文書處理軟體中,聰明的人會用 ODS 把那個表格單獨存成 rtf 檔。但如果要配適的模式很多,要用到很多 procedure,最好還是用一些 macro 來解決冗長的程式碼。Angelina D. Tan, Nancy Dilehl, Jay N. Mandrekar 在 SAS Global Forum 2007 (SUGI 今年把名稱改成 SAS Global Forum了)中發表了三個「懶人 macro 包」,讓懶得寫那麼多 SAS code 的人能夠輕鬆配適模式,並且用 ODS 和 proc report 把參數估計表美美的存出來。
Regression model
macro 程式如下:
%macro pReg (dsn=, varlist=, numvars=, respvar=, outdsn=table);
%do j=1 %to &numvars.;
%let var2=%scan(&varlist.,&j.,' ');
ods select none;
ods output ParameterEstimates=work.pe&j. ;
proc reg data=&dsn.;
model &respvar. = &var2. ;
run;
ods select all;
data pe&j.;
set pe&j.;
keep Variable Estimate StdErr tValue Probt ;
if Variable="Intercept" then delete;
run;
%if &j.=1 %then %do;
data &outdsn.;
set pe1;
run;
%end;
%else %do;
data &outdsn.;
set &outdsn. pe&j.;
run;
%end;
%end;
%mend pReg;
這個 macro 包含五個參數:
- dsn = 輸入資料來源檔
- varlist = 自變數
- numvars = 自變數個數
- respvar = 依變數
- outdsn = 輸出參數估計表的資料檔名(預設值=table)
%pReg (dsn =tana.fitness,
Varlist =Age Weight RunTime RunPulse RestPulse MaxPulse,
numvars =6,
respvar =Oxygen,
outdsn =preg);
此範例是使用在 tana 這個 library 裡面的 fitness 資料檔。自變數是 Age、Weight、RunTime、RunPulse、RestPulse 和 MaxPulse 共計六個。依變數是 Oxygen,而參數估計表則另存到 preg 這個資料檔裡面。
然後便可以用下面這個 prog report 指令把參數估計表很完美地打印在 preg.doc 這個檔案裡面。我建議使用者不用太需要理會裡面的設定,只要記得把 ods rtf 後面的設定改成你要的路徑和檔名即可。當然如果你想要用別的 title 的話也可以把 title1 後面那串字改掉。不過基本上其他的程式碼都不需要變動。
ods rtf file='h:\ibm\preg.doc';
title1 'Simple Linear Regression Model';
proc report data=preg box nowd split=' ';
column Variable Estimate StdErr tValue Probt ;
define Variable / display;
define Estimate / display;
define StdErr / display;
define tValue / display;
define Probt / display;
compute probt;
if probt <= 0.05 then call define('_c5_','style','style=[font_weight=bold]'); endcomp; run; ods rtf close;

如果你覺得這種兩階段的程式還是太麻煩,可以把上面的 proc report 程序丟進 pReg 裡面,但必須把 ods rtf 那行改成 macro 變數: ods rtf file="&filename"; 並將 macro 程式第一行改成: %macro pReg (dsn=, varlist=, numvars=, respvar=, outdsn=table, filename);
Logistic regression model
macro 程式如下:
%macro pLogistic (dsn=, varlist=, numvars=, respvar=, outdsn=table);
%do j=1 %to &numvars.;
%let var2=%upcase(%scan(&varlist.,&amp;amp;amp;j.,' '));
ods select none;
ods output ParameterEstimates=work.pe&j. OddsRatios=work.or&amp;amp;amp;j. ;
proc logistic data= &dsn. descending;
model &respvar.= &amp;amp;amp;var2. /link=logit ;
run;
ods select all;
data pe&j.;
length Independent $20;
set pe&j.;
rename ProbChiSq=Waldp;
keep Independent Estimate StdErr WaldChiSq ProbChiSq;
Independent="&var2.";
if upcase(Variable)="&var2.";
run;
proc sort data=pe&j.;
by Independent;
run;
data or&j;
length Independent $20;
set or&j.;
rename OddsRatioEst=OREst;
keep Independent OddsRatioEst LowerCL UpperCL;
Independent="&var2.";
if upcase(Effect)="&var2.";
run;
proc sort data=or&j.;
by Independent;
run;
data all&j.;
merge pe&j. or&amp;amp;amp;j.;
by Independent;
run;
%if &j.=1 %then %do;
data &outdsn.;
set all1;
run;
%end;
%else %do;
data &outdsn.;
set &outdsn. all&amp;amp;amp;j;
run;
%end;
%end;
%mend pLogistic;
同樣有五個參數,定義完全和 pReg 雷同。在此不多加描述。
使用範例如下:
%pLogistic (dsn =tana.icu,
Varlist =AGE SEX SER CAN CRN INF CPR SYS HRA PRE TYP FRA PO2 PH PCO BIC CRE,
Numvars =17,
Respvar =STA,
outdsn =plog);
然後用 proc report 列印參數估計表:
ods rtf file=''h:\ibm\plogistic.doc';
title1 'Univariate Logistic regression for endpoint status (Lived, Died)';
proc report data=plog box nowd split=' ';
column Independent Estimate StdErr WaldChiSq Waldp OREst LowerCL
UpperCL;
define Estimate / display;
define StdErr / display;
define WaldChiSq / display;
define Waldp / display;
define OREst / display;
define LowerCL / display;
define UpperCL / display;
compute orest;
if waldp <0.05> 1 then do;
call define('_c5_','style','style=[background=yellow]');
call define('_c6_','style','style=[background=yellow]');
end;
endcomp;
run;
ods rtf close;
這個打印出來的參數估計表比較炫,會把顯著的參數用高亮度的黃色標記出來。

Cox PH model
macro 程式如下:
%macro phReg (dsn=, varlist=, numvars=, respvar=, censvar=, censval=,
outdsn=table);
%do j=1 %to &numvars.;
%let var2=%upcase(%scan(&varlist.,&amp;amp;amp;j.,' '));
ods select none;
ods output ParameterEstimates=work.pe&j.;
proc phreg data = &dsn. ;
model &respvar.*&censvar.(&censval.)= &amp;amp;amp;amp;var2./rl;
run;
ods select all;
data pe&j.;
length Independent $15 ;
set pe&j.;
keep Estimate StdErr Independent ProbChiSq HazardRatio
HRLowerCL HRUpperCL;
Independent="&var2.";
if upcase(Variable)="&var2.";
run;
proc sort data=pe&j.;
by Independent;
run;
data all&j.;
merge pe&j. ;
by Independent;
run;
%if &j.=1 %then %do;
data &outdsn.;
set all1;
run;
%end;
%else %do;
data &outdsn.;
set &outdsn. all&amp;amp;amp;j.;
run;
%end;
%end;
%mend phReg;
這個 macro 使用到的參數有七個:
- dsn = 資料來源檔
- Varlist = 自變數名稱
- Numvars = 自變數個數
- RespVar = 依變數
- CesnVar = 設限變數名稱
- CensVal = 設限變數值
- outdsn = 輸出參數估計表的資料檔名(預設值=table)
%phReg (dsn =tana.Myeloma,
Varlist =LogBUN HGB Platelet Age LogWBC Frac LogPBM Protein
SCalc,
Numvars =9,
Respvar =Time,
Censvar =VStatus,
Censval =0,
outdsn =phreg);
最後還是要用 ODS 和 proc report 把參數估計表存出來:
ods rtf file=''h:\ibm\phreg.doc';
title1 'Univariate PHREG for endpoint status (Alive, Dead)';
proc report data=phreg box nowd split=' ';
column Independent Estimate StdErr ProbChiSq HazardRatio
HRLowerCL HRUpperCL;
define Independent / display;
define Estimate / display;
define StdErr / display;
define ProbChiSq / display;
define HazardRatio / display;
define HRLowerCL / display;
define HRUpperCL / display;
compute probchisq;
if probchisq <= 0.05 then call define('_c4_','style','style=[font_weight=bold font_style=italic]');
endcomp;
run;
ods rtf close;

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Angelina Tan
Mayo Clinic, Division of Biostatistics
200 First Street SW
Rochester MN 55905
Phone: 507-284 5743
Fax: 507-266 2477
Email: tan.angelina@mayo.edu
2007年4月13日 星期五
STOP! WAIT! GO! See What Traffic-Lighting Can Do For You
原文載點:http://www.nesug.info/Proceedings/nesug05/pos/pos1.pdf
我以前經常用 ODS 系統把報表和結果輸出成 rtf 或 html 檔,rtf 主要的優點是好編輯,html 主要的優點是印出來很華麗。但近日在 NESUG 上面看到一篇文章,裡面居然提到 ODS 也可以生出 EXCEL 檔(.xls)。我比較推薦這篇文章的另一個原因是,從 ODS 輸出的 xls 檔,不但可以做一些版面配置,而且還可以直接在 SAS 裡面呼叫 EXCEL 開啟檔案,並能進行同步修改。雖然這個功能作者只有用在 PROC PRINT 的程序上,但這可以解決一些編寫程式的問題,文末再來敘述。先介紹一下這個 ODS 功能的用法。
設定文字顏色格式
利用 PROC FORMAT 來指定哪些數據用哪些顏色,套入 PROC PRINT 中,再利用 ODS 輸出的功能讓效果呈現在 EXCEL 報表上。程式如下所示:
PROC FORMAT 的功能就是在設定數據在某個範圍之下被分配到哪種顏色。一般的 SAS 程式要套用 PROC FORMAT 的設定都要在之後的程式加上 FORMAT [var] [varfmt.]; 的語法,但在 PROC PRINT 下,可直接在想要套用的便樹後面加上 style 的選項。foreground 即表示文字顏色,foreground=sigf. 即表示將 PROC FORMAT 對 sigf 的設定套用在 foreground 上。然後,使用 msoffice2k 讓 ODS 把 PROC PRINT 的結果輸出到 EXCEL,並把檔名設定為 significance)foreground.xls。這個檔案會存在 SAS 的預設目錄下,如果要存在指定的目錄,就要把完整路徑寫上去。path=odsout 的功能不清楚,但當我實際使用在別的資料集時,會出現錯誤訊息。後來把 path=odsout 拿掉後可以順利產生 .xls 檔,沒有任何異狀。所以若使用者有同樣情況,可以大膽地把這個選項拿掉。
產生的檔案大概長的像下圖所示:

設定背景顏色格式
能設定文字顏色就一定可以設定背景顏色。語法和上述程式沒有太大改變,只是將 foreground 改成 background 而已。程式如下:
同樣地,先用 PROC FORMAT 設定好背景顏色出現的條件,然後把他代入 background 即可。產生的效果如下所示:

加星號
有時候我們會在不同的顯著型 p-value 後面打上不同個數的星號,如 <0.05>Proc format;
picture sigstar low-<0.0010='9.9999***'
0.0011-<0.0501='9.9999**'
0.0501-<0.1001='9.9999*'
other='9.9999';
run;
Ods msoffice2k file=’significance_stars.xls’ path=odsout style=styles.minimal;
Proc print data=yourlib.yourdata noobs label uniform;
var xlab xval totaln totper nsumn colpern nsumno colperno chisqp;
format chisqp sigstar.;
title1 'Significance Stars Traffic Lighting';
Title1 ‘Background Traffic Lighting’;
Run;
Ods msoffice2k close;
兩個地方稍微和之前的程式不同。一是在 PROC FORMAT 中指定格式變數的宣告語法從 value 改成 picture。另外,要套用 sigstar 的語法也要變回一般常用的 FORMAT [var] [varfmt.]; 格式。附帶一提,sigstar 在 PROC FORMAT 裡面設定星號時都會在前面加上 9.9999,這會將被格式化的變數(chisqp)變成小數點四位的格式。比方說原始數據是 1,就會被改成 1.0000,格式被改後才會開始加上星號,不過如果數據是落在 other 的範圍內,就不會有任何變動。
做出來的樣子如下所示:

ODS msoffice2k 的好處不止在於可以把 PROC PRINT 的檔案輸出成 EXCEL 格式,對 SAS 不熟的人,可以直接在 SAS 內開啟的 EXCEL 進行計算的動作,也可以任意更改欄位順序。如果只想用裡面一小部分的檔案,也可以複製需要的資料,然後貼到新的 edit 視窗,用 data step 的步驟馬上建立新的資料集。總之這可以活用的彈性很大,很適合初學者使用。
原文內還有關於如何在 PROC TABULATE 內著色的教學,不過我覺得不是很實用,所以就不寫了。有興趣的人可以直接下載原文來參考。
CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Louise Hadden
Abt Associates Inc.
55 Wheeler St.
Cambridge, MA 02138
Work Phone: 617-349-2385
Fax: 617-349-2675
Email: louise_hadden@abtassoc.com
我以前經常用 ODS 系統把報表和結果輸出成 rtf 或 html 檔,rtf 主要的優點是好編輯,html 主要的優點是印出來很華麗。但近日在 NESUG 上面看到一篇文章,裡面居然提到 ODS 也可以生出 EXCEL 檔(.xls)。我比較推薦這篇文章的另一個原因是,從 ODS 輸出的 xls 檔,不但可以做一些版面配置,而且還可以直接在 SAS 裡面呼叫 EXCEL 開啟檔案,並能進行同步修改。雖然這個功能作者只有用在 PROC PRINT 的程序上,但這可以解決一些編寫程式的問題,文末再來敘述。先介紹一下這個 ODS 功能的用法。
設定文字顏色格式
利用 PROC FORMAT 來指定哪些數據用哪些顏色,套入 PROC PRINT 中,再利用 ODS 輸出的功能讓效果呈現在 EXCEL 報表上。程式如下所示:
Proc format;
Value sigf low-<0.0011=’Green’
0.0011-<0.0501=’Red’
0.0501-<0.1001=’Blue’
other=’Black’;
run;
Ods msoffice2k file=’significance_foreground.xls’path=odsout style=styles.minimal;
Proc print data=yourlib.yourdata label uniform;
Var var2 chisq;
Var chisqp / style={foreground=sigf.};
Var chisqdf;
Id var1;
Title1 ‘Foreground Traffic Lighting’;
Run;
Ods msoffice2k close;
PROC FORMAT 的功能就是在設定數據在某個範圍之下被分配到哪種顏色。一般的 SAS 程式要套用 PROC FORMAT 的設定都要在之後的程式加上 FORMAT [var] [varfmt.]; 的語法,但在 PROC PRINT 下,可直接在想要套用的便樹後面加上 style 的選項。foreground 即表示文字顏色,foreground=sigf. 即表示將 PROC FORMAT 對 sigf 的設定套用在 foreground 上。然後,使用 msoffice2k 讓 ODS 把 PROC PRINT 的結果輸出到 EXCEL,並把檔名設定為 significance)foreground.xls。這個檔案會存在 SAS 的預設目錄下,如果要存在指定的目錄,就要把完整路徑寫上去。path=odsout 的功能不清楚,但當我實際使用在別的資料集時,會出現錯誤訊息。後來把 path=odsout 拿掉後可以順利產生 .xls 檔,沒有任何異狀。所以若使用者有同樣情況,可以大膽地把這個選項拿掉。
產生的檔案大概長的像下圖所示:

設定背景顏色格式
能設定文字顏色就一定可以設定背景顏色。語法和上述程式沒有太大改變,只是將 foreground 改成 background 而已。程式如下:
Proc format;
Value sigb low-<0.0011='Red'
0.0011-<0.0501='Yellow'
other='Green';
run;
Ods msoffice2k file=’significance_background.xls’ path=odsout style=styles.minimal;
Proc print data=yourlib.yourdata noobs label uniform;
var xlab xval totaln totper nsumn colpern nsumno colperno;
var chisqp / style={background=sigb.};
title1 'Significance Background Traffic Lighting';
run;
Ods msoffice2k close;
同樣地,先用 PROC FORMAT 設定好背景顏色出現的條件,然後把他代入 background 即可。產生的效果如下所示:

加星號
有時候我們會在不同的顯著型 p-value 後面打上不同個數的星號,如 <0.05>Proc format;
picture sigstar low-<0.0010='9.9999***'
0.0011-<0.0501='9.9999**'
0.0501-<0.1001='9.9999*'
other='9.9999';
run;
Ods msoffice2k file=’significance_stars.xls’ path=odsout style=styles.minimal;
Proc print data=yourlib.yourdata noobs label uniform;
var xlab xval totaln totper nsumn colpern nsumno colperno chisqp;
format chisqp sigstar.;
title1 'Significance Stars Traffic Lighting';
Title1 ‘Background Traffic Lighting’;
Run;
Ods msoffice2k close;
兩個地方稍微和之前的程式不同。一是在 PROC FORMAT 中指定格式變數的宣告語法從 value 改成 picture。另外,要套用 sigstar 的語法也要變回一般常用的 FORMAT [var] [varfmt.]; 格式。附帶一提,sigstar 在 PROC FORMAT 裡面設定星號時都會在前面加上 9.9999,這會將被格式化的變數(chisqp)變成小數點四位的格式。比方說原始數據是 1,就會被改成 1.0000,格式被改後才會開始加上星號,不過如果數據是落在 other 的範圍內,就不會有任何變動。
做出來的樣子如下所示:

ODS msoffice2k 的好處不止在於可以把 PROC PRINT 的檔案輸出成 EXCEL 格式,對 SAS 不熟的人,可以直接在 SAS 內開啟的 EXCEL 進行計算的動作,也可以任意更改欄位順序。如果只想用裡面一小部分的檔案,也可以複製需要的資料,然後貼到新的 edit 視窗,用 data step 的步驟馬上建立新的資料集。總之這可以活用的彈性很大,很適合初學者使用。
原文內還有關於如何在 PROC TABULATE 內著色的教學,不過我覺得不是很實用,所以就不寫了。有興趣的人可以直接下載原文來參考。
CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Louise Hadden
Abt Associates Inc.
55 Wheeler St.
Cambridge, MA 02138
Work Phone: 617-349-2385
Fax: 617-349-2675
Email: louise_hadden@abtassoc.com
訂閱:
文章 (Atom)