2008年6月10日 星期二

Learning PROC REPORT by Comparison

原文出處:
http://www2.sas.com/proceedings/forum2008/170-2008.pdf




此文是以學習proc report並且比較與該程序有相似的程序如proc print, proc tabulate及proc means等



1.與proc print比較
當有資料欲做初步的顯示時通常可利用print的動作將資料秀出,而proc report則也能做相同的動作
如下為proc print的範例(資料來自主程式內的範例,可直接使用)

title 'Simeple Listing' ;
proc print data=sashelp.class ;
var name sex age height weight ;
title2 'PROC PRINT' ;
run ;



結果如下圖

其中的資料各變項僅需在proc print的附屬語法var後面打上欲呈現的變項即可

而在proc report部分語法如下

proc report data=sashelp.class nowd headskip ;
column name sex age height weight ;
define sex / width=3 ;
title2 'PROC REPORT' ; run ;



其中proc report後方的附屬語法:

nowd可以抑制該程序不產生獨立的報告視窗,其效果有如proc print一樣皆將結果輸出在output視窗上,然而獨立的報告視窗有其好處,例如可及時更改該變項顏色或屬性,方便報表輸出的可讀性.

headskip則是修飾報表中變項欄位與第一觀察值的距離

語法中column則與proc print中var效果相同,一樣是宣告欲呈現的變項語法

define則為定義某變項的資料屬性例如後面加上 sex /width=3 ,則宣告sex變項長度為3

根據上述proc report語法,其結果如下,會與proc print輸出報表相似



若常用 proc print功能的人眼尖的話因該會發現print報表其實有個預設值OBS(觀察值序號)
如下圖

而proc print可透過語法將此觀察值序號開啟或關閉,方法如下(只要打上noobs即可關閉)

title 'Simeple Listing' ;
proc print data=sashelp.class noobs ;
var name sex age height weight ;
title2 'PROC PRINT' ;
run ;



然而proc report其實沒有直接提供觀察值序號的功能,
不過可以透過語法的撰寫來達到相似的功能
proc report語法如下

proc report data=sashelp.class nowd headskip ;
column Obs name sex age height weight ;
define sex / width=3 center ;
define age / width=5 ;
define height / format=6.1 ;
define weight / format=6.1 ;
define obs / computed ;
compute obs ;
count+1 ;
obs=count ;
endcomp ;

title2 'PROC REPORT, again' ;
run ;


上述語法中,先在colume後先建立一空變項Obs
接著再宣告Obs格式並利用computed再處理該變項特性值
結果如下圖,會與proc print相似





2.配合sorted listing功能

當資料利用proc print程序列出時,欲先將性別sex變項作排序,其語法如下

proc sort data=sashelp.class out=class ;
by sex ;
run ;
title 'Sorted Listing' ;
proc print data=class ;
var name age ;
by sex ;
id sex ;
title2 'PROC PRINT' ;
run ;

其結果如下



而proc report程序也是能做到上述排序資料的功能,語法如下只要在define後面加個order宣告

proc report data=sashelp.class nowd headskip ;
column sex name age ;
define sex / order width=3 ;
break after sex / skip ;
title2 'PROC REPORT' ;
run ;

其結果如proc print相似如下


而在語法中用到 break after sex / skip ;
則是將報表作斷行的動作,也可將after改為before,
其目的可在後續作資料加總時修改報表板面



3.列出排序後子項的總合
利用proc print加入sumby sex語法,即能表現出sex變項排序後子項目的加總


proc print data=class ;
var name age ;
by sex ;
id sex ;
sumby sex ;
title2 'PROC PRINT' ;
run ;

其結果如下紅框處



而若利用proc report語法呈現如上述的結果報表時,需要有一些宣告

proc report data=sashelp.class nowd ;
column sex name age ;
define sex / order width=3 ;
define age / analysis sum format=4.;
break before sex / skip ;
break after sex / summarize ol ;
rbreak after / summarize dol ;

title2 'PROC REPORT' ;
run ;



其中analysis sum是宣告age變項是可分析可加總

break before sex / skip ;則為依照sex變項作斷行break,斷行的方式為向前(before)斷行並空格(skip),若將skip改為page則斷行會跳頁

break after sex / summarize ol;則是宣告在sex變項斷行後作加總(summarize)的動作並且給予上標單槓符號(ol)----方便報表閱讀

rbreak after / summarize dol ;則是指變項最後斷行的處理(rbreak),將變項做總加總(summarize)的動作,並且給予上標雙槓符號(dol)====

結果如下圖

註:上標符號可改為下標如:ul dul,並且可在獨立視窗時(未宣告nodw時)打上color=顏色(red)

接下來的語法是將上述作一些美化的動作,語法如下

proc report data=sashelp.class nowd ;
column sex sex2 name age ;
define sex / order width=3 noprint ;
define sex2 / computed 'Sex' ;
define age / mean format=best4. ;
break before sex / skip ;
break after sex / summarize ol ;
rbreak after / summarize dol ;
compute sex2 / character length=15 ;
sex2=sex ;
endcomp ;
compute after sex ;
sex2='Average for ' || sex ;
endcomp ;
compute after ;
sex2='Overall Average' ;
endcomp ;

title2 'PROC REPORT and more' ;
run ;


語法中第二行column後多加一個新變項叫做sex2其用意是增加sex的相同變項並給予改名以及後續的應用

在第三行noprint則是將原有的Sex變項作隱藏(可以不打此語法)

在第四行時則定義sex2的變項名稱為"Sex"(有點是說原Sex變項以用來做排序而後面的Sex2則是篡位原來Sex的標題"label")

第九行至第十一行是命名Sex2作為原Sex的標題項目(因為原Sex已被用來做排序了,所以新增Sex2來覆蓋原來的功用)

第十二行至第十四行則為每個sex分類break斷行後的平均值做個標題,其中sex2='Average for ' || sex ;只是說將sex2更名為Average for || sex(F or M ),而||是SAS連結文字用的符號

同理第十五至第十七則是sex2='Overall Average' ;最後為總平均的標題更名為Overall Average

其結果如下圖


接下來則是在把上述的結果報表再次的作修飾的動作


proc format ;
value $gender 'F'='females'
'M'='males' ;
run ;

proc report data=sashelp.class nowd headline ;
column sex name age ;
define sex / order width=3 ;
define age / mean ;
break after sex / skip ;
compute after sex ;
text='Average for ' || strip(put(sex, $gender.)) || ' is ' || put(age.mean, 4.1) ;
line ' ';
line text $40. ;
endcomp ;

compute after ;
line 'Overall Average is ' age.mean 4.1 ;
endcomp ;

title2 'PROC REPORT and more, again' ;
run ;



在第一行至第四行為proc format語法,其用意是宣告gender這個新變項被引用時其值F改為females,M改為males

在第五行時proc report後加上一個宣告headline顧名思義就是加個標頭線

在第八行時定義age做平均(mean)的計算並且呼應後面幾行用到的語法age.mean
若定義為總和sum時後面幾行的語法改為age.sum

第十行至第十三行不同於上一個範例語法的使用,此次則是新增一個類似文字敘述的語法
在第十一行先宣告text文字敘述的特性,其中strip()則為將文字變項前後之間做縮排的動作,也就是將
'Average for '與sex變項與' is '三者之間做縮排(若把strip()取消就可以看出差異點了),而put語法則是導入age.mean資料並且宣告其字元長度(4.1為4個字元長且小數點取1位)
接著第十二行則是新增行並以空白''做為表現,也可改為line '--------------------------';(有點類似自行做圖)
在第十三行則是將剛剛的text文字做使用的動作並且給予字元特徵40個字元長度

第十五行至第十七行與上一個範例類似,在最後做總平均的計算

其結果如下





4.與PROC TABULATE做比較

proc tabulate在SAS中是用來歸納特定變項的基本統計資料,例如平均數、樣本數等

其語法如下


title 'Summary Statistics' ;
proc tabulate data=sashelp.class ;
class sex ;
var age ;
table sex, age*(n*f=4. mean*f=6.2) ;
title2 'PROC TABULATE' ;
run ;


其中 class 指定分層變項,var 為分析變性
proc tabulate程序主要語法為table的宣告
其中先以sex作報表分類再以逗號區隔計算age的樣本數(n)、平均數(mean);而括號內f為宣告格式

結果如下圖


而在proc report語法中可以做出類似的報表
語法如下

proc report data=sashelp.class nowd split='~' box ;
column sex age age=avg_age ;
define sex / group width=3 ;
define age / n 'N' format=4.0 width=4;
define avg_age / mean 'Average~Age' format=6.2 width=7;
title2 'PROC REPORT' ;
run ;


眼尖的話因該就會發現其實只是要proc report程序做點外觀的變化,也就是增加box的宣告
結果如下圖

或者是可以把box改為headline的宣告其結果就如下圖



列聯表的應用
想到列聯表因該就會想到proc freq的使用
proc tabulate則是可以做出類似的輸出
語法如下

options missing='0' ;
title 'Cross-tabulation' ;
proc tabulate data=sashelp.class ;
class sex age ;
table age, sex*n*f=4. ;
title2 'PROC TABULATE' ;
run ;

上述語法只是要求顯示樣本數而已
其結果如下



利用proc report語法也能求出類似報表
語法如下
proc report data=sashelp.class nowd headline ;
column age sex ;
define age / group ;
define sex / across width=3 right ;
title2 'PROC REPORT' ;
run ;

語法across是用來宣告sex變項做交叉表的分類,而因沒有再分析其他變項,則sex變項僅計算其次數(n)

其結果如下圖



若想做較複雜的列聯關係表,如性別與年齡分層後的身高平均
如下為proc tabulate提供的做法

options missing='?';
title 'Cross-tabulation with Summary' ;
proc tabulate data=sashelp.class ;
class sex age ;
var height ;
table age, sex*height*mean*f=6.1 ;
title2 'PROC TABULATE' ;
run ;

如下圖僅是根據age, sex分層將height計算其平均




而proc report的做法也有所相似如下

proc report data=sashelp.class nowd split='~' headline ;
column age sex, height ;
define age / group ;
define sex / across '__Sex__' width=3 right ;
define height / analysis mean 'Average~Height'
format=6.1 width=8 ;

title2 'PROC REPORT' ;
run ;



增加, height 用來宣告sex分類下的顯示
define height / analysis mean 'Average~Height'
format=6.1 width=8 ;
的宣告計算其結果

其結果如下



若想計算列聯表中樣本數的百分比資料,有如proc freq所計算的百分比
在proc tabulate語法如下

title 'Percentages' ;
proc tabulate data=sashelp.class ;
class sex ;
table sex, n="樣本數" pctn="百分比";
title2 'PROC TABULATE' ;
run ;


僅是在table做一個計算的宣告 pctn 計算Sex變項的百分比

結果如下圖



而利用proc report的方式語法如下

proc report data=sashelp.class nowd box ;
column sex N pctn ;
define sex / group width=3;
define n / width=5 ;
define pctn / '%' format=percent7.1 ;
title2 'PROC REPORT' ;
run ;


結果如下圖





5.與PROC MEANS做比較


最後若想要做出有如proc means程序一樣能夠提供多種基本描述性統計資料
其語法如下

title 'Summary Statistics 2' ;
proc means data=sashelp.class mean std min max maxdec=1;
class sex ;
var height ;
title2 'PROC MEANS' ;
run ;

proc means有本身預設的描述性統計結果的顯示,而上述則欲顯示平均、標準差、最小值及最大值
其結果如下




如利用proc report的語法欲做出如proc means類似報表,其語法如下

proc report data=sashelp.class nowd split='~' headline ;
column sex height, (n mean std min max) ;
define sex / group width=3 ;
define height / '__Height__' ;
define n / 'N' width=3 ;
define mean / 'Mean' format=5.1 ;
define std / 'Std~Dev' format=5.2 ;
define min / 'Min' format=5.1 ;
define max / 'Max' format=5.1 ;

title2 'PROC REPORT' ;
run ;

上述語法是將各描述性統計值須先做宣告的動作
其結果如下

2 則留言:

TRH JCorgi 提到...

請問
當我的主項"Variable"為
Age
Gender
Height
Weight
BMI
次項"Statistics"為
n
Mean
Median

Female
Male

n
Mean
Median

n
Mean
Median

n
Mean
Median
然而我在使用Proc Report時
第一頁會剛好截在主項BMI,其次項資訊會呈現在下一頁,
該怎麼處理才能使他利用主項去分割? (就是把BMI拿到下一頁)

謝謝

Kingbee 提到...

請去PTT的統計版問
那邊SAS神人不少........
已不使用SAS 好多N年了.........忘光了 sorry