Picturing Your Formats with PROC FORMAT 用 PICTURE statement 描繪你的格式

前言

對於大部分 SAS 使用者來說,在產製報表時都會遇到格式 (Formats) 的問題。SAS 有許多 formats 可供使用,但是總會遇到沒有適合的 formats,例如行動電話格式 0912-345-678 或新臺幣的格式NTD等情況。

這時候 PROC FORMAT 的 PICTURE statement 就是最好的選擇,它能夠讓我們自訂任何想要的格式(只要發揮想像力和創意)。一起來看看如何使用 !


PROC FORMAT picture statement

如果說 PROC FORMAT 的 VALUE statement 是像譯碼簿一般指定變項如何分組,那麼 PICTURE statement 就是格式的繪畫布(模板),使用者可以自由的揮洒、自訂想要的格式。

PICTURE statement 所設定的是「呈現的格式」,因此不同的數值會隨所設定的模版而變化,例如:

proc format;
picture years low - high = '000 yrs';
run;

proc print data=test; format Age YEARS.; run;

low →最小值
high →最大值
low – high →所有數值範圍
‘000 yrs’ →格式指定為三位數,且後續接 yrs

我們把 YEARS 這個模板和變項 Age 連結之後,Age 就會隨著本身的數值而改變。

此由可知 PICTURE statement 利用單引號內的內容來指定我們想要的格式 (最長不超過四十個字元)。而字元有三種類型,分別為位數選擇器 (digit selectors)、訊息字元 (message characters) 和指令 (directives)。這三種類型雖然各有不同,但同樣都是以單引號框住想要呈現的 formats 即可完成指定。


位數選擇 Digit Selectors

位數選擇器是 PICTURE statement 最常用也是最容易混淆的部分,這裡我們試著簡單說明個。

位數選擇器是由一連串的數字所組成,而一個 picture format 模板最多可指定 16 個數字。這一串數字的功能就是「佔住位子」,把想要呈現的數值的位數以0到9任一個數字佔住。

位數選擇器雖然可使用 0 到 9 的數字,但實際上只分為二個部分:

0 → 選擇性的佔住位子。如果以 0 佔住了這個位子,而原始數據有這個位數的值,就呈現該值;如果沒有值,則留下空白

非 0 →絕對性的佔住位子,如果以非0數值佔住了這個位子,而原始數據有這個位數的值,就呈現該值;如果沒有值則以「0」表示。

我們直接看個例子。

proc format;
picture pictureA low-high='00000';
picture pictureB low-high='99999';
picture pictureC low-high='12345';
picture pictureD low-high='00999';
picture pictureE low-high='009.00';
run;

data a; input age;
datalines;
11
22
33
44
;

proc print data=a; format age pictureA.; run;
proc print data=a; format age pictureB.; run;
proc print data=a; format age pictureC.; run;
proc print data=a; format age pictureD.; run;
proc print data=a; format age pictureE.; run;

由結果我們可以注意到幾個重點:

  1. 位數選擇器指定的位數(所佔的位子),會影響最後顯示的樣貌。通常會依原始數據的位數來指定,避免過多位數或變成以零補上。

  2. 1到9 和 9 的功能是完全一樣的,所以通常習慣以 9 表示非 0 的位數選擇器

  3. 位數選擇器若有小數點,則小數點後的位數一律視作絕對性的佔住位子(也就是等同於填入非零數的選擇器),原始數據沒有小數點之後的值的話,預設仍以 0 補上。


訊息字元 Message Characters

相對於位數選擇器,訊息字元可以包含非數字的字元在模板裡,例如電話號碼:

proc format;
picture tel low-high='9999-9999';
run;

已結果可知,原始的電話號碼多了「-」增加了閱讀的方便性。

這裡要注意的是「SAS 預設模板的開頭一定要是數字」,如果我們想在電話號碼前加上區碼,例如(02)時該怎麼做呢? 這時候就可以呼叫 PREFIX= option

proc format;
picture tel2
low - high = '00) 0000-0000' (prefix='(' );
run;

PREFIX= option 就如同字面上的解釋,可以在顯示格式的最前面,加上任何我們想要的文字或符號,繞過預設模板的開頭一定要是數字的限制。以此例來說,格式就可以顯示為 (08)、(02) 等括號開頭的區碼。


日期和時間指令 Day and Time Directives

PICTURE formats 的第三種類型是日期與時間的指令。顧名思義,這類的指令可以方便我們指定想要的日期與時間格式,指令皆以百分比符號 %開頭。

與日期相關的指令有:

proc format;
picture dateA(default=30) low-high='%y-%b-%d' (datatype=date);
picture dateB(default=30) low-high='%Y-%B-%A' (datatype=date);
run;

default=30 →設定預設的 format長度
datatype=date →指定欲呈現的格式是日期 (date)

↑↑↑這裡可以發現,年份(%y)或是日期(%d) 由於是簡化格式,原始數據只有個位數時只會顯示一位數,若想要讓格式的長度保持一致,可以簡單在 format 裡補零如下:

proc format;
picture dateC(default=30) low-high='%0y-%B-%0d' (datatype=date);
run;

此外,這裡要另外注意的是,上述的語法會和 SAS 的版本有關;如果使用的是繁體中文版的 SAS,星期和月份方面就會出現中文 (也就不會有星期的英文縮寫),英文版則不會有這個問題。


其他常用的 option

DEFAULT= Option

DEFAULT= Option 在前面我們已經有見過了。他的功能是讓我們指定的格式有充分的長度來顯示。如果沒有指定長度,SAS 預設會以我們指定的模板長度 (例如 ‘%Y-%B-%A’,9個位元)來顯示。所以在指定 format 時別忘記指定長度,否則會顯示異常(長度不足會被截斷)。


FILL= Option

有時在指定模板時,會遇到原始數據位數不足的情況,如果不想補零 (例如 ‘9999’) 或不想空白 (例如 ‘0000’),這時候可以利用 FILL= option 補上我們所指定的字元:

proc format;
picture money
low - high = '000,000.00' (prefix='NT' fill='*');
run;

這裡要注意的是:

  1. FILL= 和 PREFIX= option 聯用時,PREFIX= 要在 PREFIX= 之前
  2. 如果模板指定的是非零的絕對佔位子(例如’9999′),則遇到位數不足仍會以零補上(亦即 FILL= 不起作用)

MULT= and ROUND option

假設我們現在有一個數值是:9876543.21

想把這個數值以百萬為單位且四捨五入呈現,該怎麼做呢? 直覺我們會想到:

proc format;
picture MillionA low-high='9.99 million';
run;

但是 SAS 卻是這樣想的:

由於原始數據小數點後有二位數,因此 SAS 會乘以十的二次方(10^2),並且無條件捨去小數點後的值,再依據所設定的模板 (‘9.99’)來呈現最後的格式,因此得到了 3.21 million。但這顯然不是我們想要的結果。

這時候我們可以利用 MULT= 和 ROUND option。

proc format;
picture MillionB (round) low - high = '9.99 million' (mult=0.0001);
run;


我舉個栗子

我們以 SAS 內建的資料集 CARS 為例,看看 PROC FORMAT picture statement 如何與 PROC TABULATE 聯用,產生我們想要的報表。

假如我們想要知道亞洲車商所生產的車型,以 TABULATE 可以簡單的呈現如下:

/*只有 TABULATE procedure*/
proc tabulate data=sashelp.cars ;
class make type;
table make='汽車製造商', type='汽車類型'*(n pctn<make>);
where origin='Asia';
run;

↑↑↑ 結果可以看到很多 missing 的 cell,顯得不甚直觀。我們試著利用 PROC FORMAT 的 PICTURE statement 設計想要的格式。

/*聯合使用 picture formats*/ 
proc format; 
picture pctpic low-high='009.99%'; /*加入%符號,並指定百分比的位數*/ 
run;

proc tabulate data=sashelp.cars;
class make type;
table make='汽車製造商', type='汽車類型'*(n pctn<make>*F=pctpic.)/printmiss misstext='0';
where origin='Asia';
run;

F=pctpic. →原本 PctN的格式以自訂的 pictpic formats呈現
printmiss →PctN 的值為 missing 的地方,仍然會 print 出來
misstext=’0′ → N為 missing的地方以 0 取代

↑↑↑以 misstext=’0′ 補零,加上 PICTURE formats 的設計,可以發現列表版面變得較為美觀,也更易讀易懂。


結語

PROC FORMAT 對許多 SAS 使用者來說常只停留在 VALUE statement 的譯碼簿功能。實際上 FORMAT 還有更多方便且實用的功能值得使用者去探索,PICTURE statement 便是其中之一;善用 PICTURE 帶來的便利之餘,也可以發揮創意,為表格呈現帶來新的思路。


參考文獻

Proc Format Uncovered. Amadeus Software.
The Power of PROC FORMAT; Updated for SAS9 Jonas V. Bilenas, JP Morgan Chase, Wilmington, DE

 

如有任何問題和意見歡迎提出