2019年9月28日 星期六

[教學示範]「使用工具:SAS」繪製統計圖_曲線圖

繪製曲線統計圖

背景介紹:混過品管圈的人,都知道年度結案時須繳交「年度結案報告」給予品管部門存查,而此份報告就含有下圖,記載著未執行品管改善前至改善中再至改善後及效果維持階段的某統計值變化趨勢。這種圖,你可以說它是折線圖,也可以說是曲線圖,不過就是數據點多不多且平不平滑而已。
數據蒐集:每月記錄一次數據,為方便繪圖及tick置中,版大會以月中的15日來標定。
目的:展示如何用SAS程式繪出此圖。


PS: 此技術也被版大應用於醫學中心同儕指標比較圖繪製。因須同時繪製數百項指標比較圖,故版大以SAS巨集方式包裏Proc sgplot來重複執行數百遍的程式。
http://www.airitilibrary.com/Publication/alDetailedMesh?docid=a0000532-201901-201903250009-201903250009-36-47



data trace;
input date:yymmdd10. level;       

format date:date9.;

 /*撰寫時,務必將設定流程宣告好,才引入數據,道理就像高速路基礎建設完成後再引入車流一樣。告訴SAS,等一下即將引入的數據,是呈yymmdd10.的格式,若SAS辨識成功,將是如下的結果。也曾有人拿程式碼來問為何他跑不出加工後變項,我當下就發現他在datalines那一串之後放了a=b*0.25(舉例) */


/*SAS系統以1960/01/01為啟始日,若日期在此日之後,將呈現相距天數(如上表的date變項內容值),反之,在此日之前,也是呈現相距天數,但以負數表之。在SAS系統中進行日期時間運算,都是以這樣的方式進行。你當然可以把它轉成正常人看得懂的格式,例如2019/09/28等格式。故當我們把外來數據轉成SAS日期值後,再套日期格式,如下面的內建格式date9.,就能達成目的。SAS內建格式種類多到令人難以想像,這是SPSS無法追上的 (註1)。*/



datalines;                           /*datalines;  ; 之間的內容,是告訴SAS要引入的資料*/
2016/01/15 59.4
2016/02/15 44.4
2016/03/15 57.1
2016/04/15 58.1
2016/05/15 65.2
2016/06/15 62.5
2016/07/15 71.9
2016/08/15 70.3
2016/09/15 89.3
2016/10/15 81.5
2016/11/15 82.1
2016/12/15 94.4
2017/01/15 91.7
2017/02/15 90.9
2017/03/15 92.9
2017/04/15 89.6

;run;

上述談及的yymmdd10.是SAS系統內建格式,以下將自訂格式,格式名稱為datefmt。
即畫出的圖,若原為2016/01/05,不要顯示2016/01/15,要顯示1601

proc format;
value datefmt  '15jan2016'd='1601'  '15feb2016'd='1602'   '15mar2016'd='1603'  '15apr2016'd='1604'  '15may2016'd='1605'  '15jun2016'd='1606'  '15jul2016'd='1607'  '15aug2016'd='1608'  '15sep2016'd='1609'   '15oct2016'd='1610' '15nov2016'd='1611'  '15dec2016'd='1612'  '15jan2017'd='1701'  '15feb2017'd='1702'  '15mar2017'd='1703'  '15apr2017'd='1704';
run;


其它常見的如性別變項,其值為1或0,在盒形圖中要呈現男性和女性,不要呈現1或0 (那當初在資料集中就寫男性和女性就好,你這樣根本就多此一舉=>錯!若資料集有上萬筆,它會影響處理效能也會增加資料集檔案大小)等,也是用這樣的手法。另,若你有50個甚至100個變項要這樣處理,可以寫在excel中,然後用SAS Enterprise Guide轉成格式群 ,就能馬上套(商業版SAS才有此軟體)。


回到主題,要畫圖了!
/*以ODS系統輸出圖形並設定長寬*/
ods graphics / imagefmt=png width=1100px height=600px;

/*利用proc sgplot程序繪圖*/
proc sgplot data=trace;

/*以series statement 繪製折線或曲線,並設定相關格式(markers可使曲線增加資料點,而此資料點的樣式,可利用markerattrs=加以改造,lineattrs=用於改造曲線樣式,datalabel則是為每個資料點增加標籤值,而datalabelattrs可改造其樣式)*/
series y=level  x=date / legendlabel = "整合率" markers  markerattrs=(symbol=circlefilled color=red  size=12)   lineattrs = (color=red   thickness = 2) datalabel datalabelattrs=(size=12) ;

1.資料點樣式 例如:markerattrs=(symbol=circlefilled color=red  size=12)

2.曲線樣式lineattrs=(pattern=1 color=red   thickness = 2)





/*設定x軸格式*/
xaxis label="西元年月" valueattrs=(size=14) fitpolicy=rotate  labelattrs=(size=14) values=('15jan2016'd to '15apr2017'd by month) ;

/*設定y軸格式*/
yaxis label="整合率(%)"  ranges= (0-8 38-100)  labelattrs=(size=14)  valueattrs=(size=14);

/*設定參考線,調整其位置、標籤值、線粗細及顏色*/
refline 71 / transparency=0.5  axis=y lineattrs=(pattern=20 color=tan thickness=3)  label="目標值(71)" labelattrs=(size=12) labelloc=inside labelpos=min;

/*設定第1個色塊。色塊視個人偏好看是否要追加。從剛剛由上寫至此,物件是一個一個疊上去的,此時在1jan2016~28jun2016區間疊上色塊,肯定會蓋到曲線,故色塊要調整透明度(transparency)。你也可先放色塊,再疊上曲線,就不會有此問題 (註2)。*/
band y=level  lower="1jan2016"d upper="28jun2016"d /transparency=0.8 fillattrs=(color=cxb2309e) legendlabel="改善前";

/*設定第2個色塊*/
band y=level  lower="1jul2016"d upper="28sep2016"d /transparency=0.8 fillattrs=(color=cx52cc62) legendlabel="改善中";

/*設定第3個色塊*/
band y=level  lower="1oct2016"d upper="28dec2016"d /transparency=0.8 fillattrs=(color=xcd9892b) legendlabel="改善後";

/*設定第4個色塊*/
band y=level  lower="1jan2017"d upper="30apr2017"d /transparency=0.8 fillattrs=(color=yellow) legendlabel="效果維持";

/*針對date變項,套用自訂格式datefmt*/
format date datefmt.;

/*調整圖說格式,keylegend statement也是一個大故事,光keylegend就可以開好幾篇文章探討此暫不談,以下內容將調整圖說內的字體大小*/
keylegend / valueattrs=(size=12);

run;
/*ODS系統收尾,並清掉title內容宣告。若前述有寫tilte1  title2...則在此可用titlen;一口氣全部清掉宣告內容值而 footnoten;也具同樣功能*/
ods graphics off; title;

另外,針對xy軸橫斷面改法,可以改用其它效果,如下:

ods graphics / imagefmt=png width=1000px height=550px;
proc sgplot data=trace;
series y=level  x=date / legendlabel = "整合率" markers  markerattrs=(symbol=circlefilled color=red  size=12)   lineattrs = (color=red   thickness = 2)
            datalabel datalabelattrs=(size=12) ;
xaxis label="西元年月" valueattrs=(size=14) fitpolicy=rotate  labelattrs=(size=14) values=('15jan2016'd to '15apr2017'd by month) ;
yaxis label="整合率(%)"  ranges= (0-8 38-100)  labelattrs=(size=14)  valueattrs=(size=14);
refline 71 / transparency=0.5  axis=y lineattrs=(pattern=20 color=tan thickness=3)  label="目標值(71)" labelattrs=(size=12) labelloc=inside labelpos=min;
band y=level  lower="1jan2016"d upper="28jun2016"d /transparency=0.8 fillattrs=(color=cxb2309e) legendlabel="改善前";
band y=level  lower="1jul2016"d upper="28sep2016"d /transparency=0.8 fillattrs=(color=cx52cc62) legendlabel="改善中";
band y=level  lower="1oct2016"d upper="28dec2016"d /transparency=0.8 fillattrs=(color=xcd9892b) legendlabel="改善後";
band y=level  lower="1jan2017"d upper="30apr2017"d /transparency=0.8 fillattrs=(color=yellow) legendlabel="效果維持";
format date datefmt.;
keylegend / valueattrs=(size=12);
styleattrs axisbreak=bracket axisextent=data;
run;
ods graphics off; title;

   styleattrs axisbreak=bracket axisextent=data; 效果


其餘效果及其名稱

更多說明

https://documentation.sas.com/?docsetId=grstatproc&docsetTarget=p1dt33l6a6epk6n1chtynsgsjgit.htm&docsetVersion=9.4&locale=ja

另,關於ranges= (0-8 38-100)寫法,也可改成ranges= (min-8 38-max)

本篇文章引用語法

data trace;
input date:yymmdd10. level;
format date:date9.;
datalines;
2016/01/15 59.4
2016/02/15 44.4
2016/03/15 57.1
2016/04/15 58.1
2016/05/15 65.2
2016/06/15 62.5
2016/07/15 71.9
2016/08/15 70.3
2016/09/15 89.3
2016/10/15 81.5
2016/11/15 82.1
2016/12/15 94.4
2017/01/15 91.7
2017/02/15 90.9
2017/03/15 92.9
2017/04/15 89.6
;run;

proc format;
value datefmt  '15jan2016'd='1601'  '15feb2016'd='1602'   '15mar2016'd='1603'  '15apr2016'd='1604'  '15may2016'd='1605'  '15jun2016'd='1606'  '15jul2016'd='1607'  '15aug2016'd='1608'  '15sep2016'd='1609'   '15oct2016'd='1610' '15nov2016'd='1611'  '15dec2016'd='1612'  '15jan2017'd='1701'  '15feb2017'd='1702'  '15mar2017'd='1703'  '15apr2017'd='1704';
run;

ods graphics / imagefmt=png width=1000px height=550px;
proc sgplot data=trace;
series y=level  x=date / legendlabel = "整合率" markers  markerattrs=(symbol=circlefilled color=red  size=12)   lineattrs = (color=red   thickness = 2)
            datalabel datalabelattrs=(size=12) ;
xaxis label="西元年月" valueattrs=(size=14) fitpolicy=rotate  labelattrs=(size=14) values=('15jan2016'd to '15apr2017'd by month) ;
yaxis label="整合率(%)"  ranges= (0-8 38-100)  labelattrs=(size=14)  valueattrs=(size=14);
refline 71 / transparency=0.5  axis=y lineattrs=(pattern=20 color=tan thickness=3)  label="目標值(71)" labelattrs=(size=12) labelloc=inside labelpos=min;
band y=level  lower="1jan2016"d upper="28jun2016"d /transparency=0.8 fillattrs=(color=cxb2309e) legendlabel="改善前";
band y=level  lower="1jul2016"d upper="28sep2016"d /transparency=0.8 fillattrs=(color=cx52cc62) legendlabel="改善中";
band y=level  lower="1oct2016"d upper="28dec2016"d /transparency=0.8 fillattrs=(color=xcd9892b) legendlabel="改善後";
band y=level  lower="1jan2017"d upper="30apr2017"d /transparency=0.8 fillattrs=(color=yellow) legendlabel="效果維持";
format date datefmt.;
keylegend / valueattrs=(size=12);
run;
ods graphics off; title;

註1

下圖套用格式為yymmdd10.



其餘常見日期格式




註2

找顏色碼的方法
從上例第一色塊,顏色碼為color=cxb2309e 它是怎麼來的?
在google敲上hex color搜尋


有二個地方可分別調整顏色及明暗,然後呈現HEX值,把#改成cx,剩餘6碼照抄,此cx7a23a8值就是sas能辨識的顏色。網路上有多個專門網站具該功能,甚至能反向傳訊,即給予hex值就能顯示其對應顏色,google一下就很多,版大不再提供。

沒有留言: