公告
[公告]
2014/01/17
由於已經是faculty的關係,不太有足夠時間寫部落格。因此更新的速度會相當緩慢。再加上近幾年來SAS GLOBAL FORUM沒有出現讓我覺得驚艷的技術文件,所以能分享的文章相對也減少許多。若有人推薦值得分享的SAS技術文件,請利用『問題討論區』告知。
2013/07/19
臉書留言板的功能因為有不明原因故障,因此特此移除。而intensedebate的留言板因管理不易,也一併移除。目前已經開啟內建的 G+ 留言系統,所以請有需要留言的朋友,可直接至『問題討論區』裡面留言。
2015年9月12日 星期六
2015年8月24日 星期一
A SAS Macro to Compute Effect Size (Cohen’s d) and its Confidence Interval from Raw Survey Data
原文載點:http://analytics.ncsu.edu/sesug/2012/SD-06.pdf
Effect size是一種量化兩個或多個變數間關係的測度。在許多臨床試驗裡面都需要這個數據。不同的研究設計需要不同種類的Effect size,其中又以Cohen's d統計量最為流行,因為他是專門用在下面這三種的研究:(1)兩個獨立群組的試後比較; (2)一個群組內的試前試後比較; (3)兩個獨立群組的試前試後差異比較。由於SAS沒有內建任何的程序來計算Effect size,所以通常需要去找線上的計算器或者自己用Excel試算表去計算。但其實Cohen's d的公式相當簡單,裡面只有用到三種元素:各組樣本,各組平均數,各組標準差。所以我在算Cohen's d時都是自己先用PROC MEANS去算出那三個元素,然後再用PROC IML去算。2012年的SESUG發表了一篇技術文件,由兩個南佛大的人公布了一個計算Cohen's d的SAS巨集程式。
Effect size是一種量化兩個或多個變數間關係的測度。在許多臨床試驗裡面都需要這個數據。不同的研究設計需要不同種類的Effect size,其中又以Cohen's d統計量最為流行,因為他是專門用在下面這三種的研究:(1)兩個獨立群組的試後比較; (2)一個群組內的試前試後比較; (3)兩個獨立群組的試前試後差異比較。由於SAS沒有內建任何的程序來計算Effect size,所以通常需要去找線上的計算器或者自己用Excel試算表去計算。但其實Cohen's d的公式相當簡單,裡面只有用到三種元素:各組樣本,各組平均數,各組標準差。所以我在算Cohen's d時都是自己先用PROC MEANS去算出那三個元素,然後再用PROC IML去算。2012年的SESUG發表了一篇技術文件,由兩個南佛大的人公布了一個計算Cohen's d的SAS巨集程式。
2014年12月18日 星期四
Generalized McNemar’s Test for Homogeneity of the Marginal Distributions
原文載點:http://www2.sas.com/proceedings/forum2008/382-2008.pdf
在配對分析裡面,McNemar's test一直是主要被拿來使用的統計分析,但這個方法有個先天上的限制是只支援二項資料。一旦資料成為多項資料時,就必須使用Generalized McNemar's test (或稱Stuart-Maxwell test)或者是Bhapkar's test。其中,Bhapkar's test是有被SAS/STAT內的程序所支援,但Generalized McNemar's test則無。Xuezheng Sun和Zhao Yang在2008年發表了一篇技術文件裡面,敘述了如何使用既有的SAS程序來執行Bhapkar's test,並且公佈了一個自製的巨集程式來執行Generalized McNemar's test。
在配對分析裡面,McNemar's test一直是主要被拿來使用的統計分析,但這個方法有個先天上的限制是只支援二項資料。一旦資料成為多項資料時,就必須使用Generalized McNemar's test (或稱Stuart-Maxwell test)或者是Bhapkar's test。其中,Bhapkar's test是有被SAS/STAT內的程序所支援,但Generalized McNemar's test則無。Xuezheng Sun和Zhao Yang在2008年發表了一篇技術文件裡面,敘述了如何使用既有的SAS程序來執行Bhapkar's test,並且公佈了一個自製的巨集程式來執行Generalized McNemar's test。
2011年10月14日 星期五
Fitting Cox Model Using PROC PHREG and Beyond in SAS
http://support.sas.com/resources/papers/proceedings09/236-2009.pdf
Cox PH 模型在倖存分析(survival analysis)被廣泛的使用。一篇發表在SAS GLOBAL FORUM 2009的技術文件解說了在 SAS 底下如何用 Cox PH 模型來計算一些重要估計量的方法,並且提供一個方便的巨集程式來簡化繁複的程式寫作和運行。
Cox PH 模型在倖存分析(survival analysis)被廣泛的使用。一篇發表在SAS GLOBAL FORUM 2009的技術文件解說了在 SAS 底下如何用 Cox PH 模型來計算一些重要估計量的方法,並且提供一個方便的巨集程式來簡化繁複的程式寫作和運行。
2011年8月16日 星期二
Wow! You Did That Map with SAS/GRAPH®?
原文載點:http://www.nesug.info/Proceedings/nesug07/np/np01.pdf
身為一個專門從事空間時間序列分析的學者我來講,每天跟不同的地圖奮鬥是很稀鬆平常的是。目前市面上最熱門的地圖分析軟體莫過於ArcGIS,但這套軟體僅提供有限的分析方法,而其主要的功能僅僅就是繪製地圖而已。如果你用了別的軟體進行分析,就必須要將結果另存新檔,然後把結果跟地圖檔一起輸入到ArcGIS裡面才能開始繪圖。想當然爾,這裡面也沒有太多強大的資料整理功能,所以一切的一切都還是要經過另外的軟體將資料結果整理好才行。如果分析和繪製地圖的動作可以一次在SAS裡面完成的話將會省下許多時間和精力。NESUG 2007年有一篇教學文件,提供一些在SAS繪製地圖的資訊。
身為一個專門從事空間時間序列分析的學者我來講,每天跟不同的地圖奮鬥是很稀鬆平常的是。目前市面上最熱門的地圖分析軟體莫過於ArcGIS,但這套軟體僅提供有限的分析方法,而其主要的功能僅僅就是繪製地圖而已。如果你用了別的軟體進行分析,就必須要將結果另存新檔,然後把結果跟地圖檔一起輸入到ArcGIS裡面才能開始繪圖。想當然爾,這裡面也沒有太多強大的資料整理功能,所以一切的一切都還是要經過另外的軟體將資料結果整理好才行。如果分析和繪製地圖的動作可以一次在SAS裡面完成的話將會省下許多時間和精力。NESUG 2007年有一篇教學文件,提供一些在SAS繪製地圖的資訊。
2011年7月9日 星期六
MCPOWER: a Flexible Macro Suite for Generating Monte Carlo Power Estimates for Linear, Logistic, and Poisson Regression Models
原文載點:http://support.sas.com/resources/papers/proceedings11/430-2011.pdf
哈佛的一位統計分析師分享了一個名為 %mcpower 的巨集程式,能夠輕鬆的完成在線性迴歸、羅吉斯迴歸以及卜瓦松迴歸的蒙地卡羅檢定力模擬與估計。
哈佛的一位統計分析師分享了一個名為 %mcpower 的巨集程式,能夠輕鬆的完成在線性迴歸、羅吉斯迴歸以及卜瓦松迴歸的蒙地卡羅檢定力模擬與估計。
2011年7月2日 星期六
Fundamental Diagnostics for Two-Level Mixed Models: The SAS ® Macro MIXED_DX
原文載點:http://support.sas.com/resources/papers/proceedings10/201-2010.pdf
在進行 mixed model 分析時,模型的檢定是相當重要但也是相當煩人的一環。幾位南卡大和南佛大的學者寫了一個巨集程式來簡化相關程式的寫作,雖然目前這個程式只能使用在 2-level model,但也是具有相當貢獻。
在進行 mixed model 分析時,模型的檢定是相當重要但也是相當煩人的一環。幾位南卡大和南佛大的學者寫了一個巨集程式來簡化相關程式的寫作,雖然目前這個程式只能使用在 2-level model,但也是具有相當貢獻。
2011年4月30日 星期六
A Grad Student ‘How-To’ Paper on Grant Prep: Preliminary Data, Power Analysis, and Presentation
原文載點:http://support.sas.com/resources/papers/proceedings10/274-2010.pdf
SAS 語法百百種,身為研究生的你/妳,有沒有想過有什麼是一定要學起來並且用在報告或論文上面?這篇技術文件整合了許多你一定得用在報告和論文的SAS程式!
SAS 語法百百種,身為研究生的你/妳,有沒有想過有什麼是一定要學起來並且用在報告或論文上面?這篇技術文件整合了許多你一定得用在報告和論文的SAS程式!
2011年3月15日 星期二
ROC Hard? No, ROC Made Easy!
SAS 裡面並沒有內建繪製 ROC 曲線的程序和語法,這和目前其他統計軟體都已經內建繪製 ROC 曲線的功能的情況比較起來,顯得相當奇怪。使用者在 SAS 的環境底下,必須先用 PROC LOGISTIC 程序將模型估計出來,再將一些報表另存新的檔案,然後才能根據這些新的資料來繪製 ROC 曲線並且計算 AUC 面積。SAS 官網有一段教學,詳情可參照 http://support.sas.com/kb/25/018.html,但繪製出來的圖形不甚美觀。Kriss Harris 在 SAS Global Forum 2010 發表了一篇技術文件,提供了一個相當實用的巨集程式 %ROC_CUTOFF 讓使用者可以在 SAS 裡面迅速且美觀地畫出 ROC 曲線。
2011年3月7日 星期一
A Macro to Create a Batch Submit SAS Program
原文載點: http://support.sas.com/resources/papers/proceedings10/092-2010.pdf
在一些很特殊的情況下,我們需要大量執行不同的 SAS 程式。若一個一個從 SAS 裡面開啟再執行,不但相當消耗時間,也不沒有太大的效率。Helen Sun 和 Cindy Wong 在 SAS Global Forum 2010 發表了一個簡易的巨集程式,讓 SAS 使用者在 PC 的視窗系統底下可以輕鬆批次地將同一個目錄底下的 SAS 程式碼給一次執行完畢。
2011年2月25日 星期五
Disagreement on Agreement: Two Alternative Agreement Coefficients
原文載點:http://www2.sas.com/proceedings/forum2007/186-2007.pdf
Kappa一致性係數是用來評量許多評分者對某一類別變數評分是否具有一致性的指標。根據公式,它是實際評定一致的次數百分比與評分者理論上評定的最大可能次數百分比的比率。但是近年來有越來越多的學者發現這個指標的不完美處。於是有許多替代性的指標被研究出來,以克服Kappa一致性係數的缺點。然而SAS並沒有對這些新的一致性指標的程式語法更新至新版的SAS中。也許我們可以期待新的一致性係數會在不久的將來被納入到SAS內建的語法,但畢竟SAS改版的頻率並沒有很高,所以還是用自製的巨集程式比較有效率。本篇教學文件主要是介紹由Kilem Gwet所發表的一階和二階一致性係數(first-order and second order agreement coefficient,簡稱AC1和AC2)在SAS裡面如何操作。其巨集程式由 Emily Blood 和 Kevin Spratt 編寫,並發表於 2007 SAS Global Forum 上。
Kappa一致性係數是用來評量許多評分者對某一類別變數評分是否具有一致性的指標。根據公式,它是實際評定一致的次數百分比與評分者理論上評定的最大可能次數百分比的比率。但是近年來有越來越多的學者發現這個指標的不完美處。於是有許多替代性的指標被研究出來,以克服Kappa一致性係數的缺點。然而SAS並沒有對這些新的一致性指標的程式語法更新至新版的SAS中。也許我們可以期待新的一致性係數會在不久的將來被納入到SAS內建的語法,但畢竟SAS改版的頻率並沒有很高,所以還是用自製的巨集程式比較有效率。本篇教學文件主要是介紹由Kilem Gwet所發表的一階和二階一致性係數(first-order and second order agreement coefficient,簡稱AC1和AC2)在SAS裡面如何操作。其巨集程式由 Emily Blood 和 Kevin Spratt 編寫,並發表於 2007 SAS Global Forum 上。
2010年8月2日 星期一
Automatically Run Fisher's Exact Test When the Chi-square Test Might Not Be Valid
Link: http://support.sas.com/resources/papers/proceedings10/096-2010.pdf
在使用PROC FREQ執行卡方檢定時,如果看到列聯表下面出現warning的訊息,就表示這個列聯表有50%以上的期望值小於五,因此程式會建議使用Fisher's exact test。然後使用者必須回到程式裡面,在tables statement後面加上一個exact的選項,再重跑一次PROC FREQ才能得到Fisher's exact test的結果。Wei Xu於SAS GLOBAL FORUM 2010發表了一個macro程式,讓電腦自動幫使用者判斷要不要進行Fisher's exact test,若需要的話會順便把Fisher's exact test的結果跑出來,使用者不需再去重新執行PROC FREQ一次。
在使用PROC FREQ執行卡方檢定時,如果看到列聯表下面出現warning的訊息,就表示這個列聯表有50%以上的期望值小於五,因此程式會建議使用Fisher's exact test。然後使用者必須回到程式裡面,在tables statement後面加上一個exact的選項,再重跑一次PROC FREQ才能得到Fisher's exact test的結果。Wei Xu於SAS GLOBAL FORUM 2010發表了一個macro程式,讓電腦自動幫使用者判斷要不要進行Fisher's exact test,若需要的話會順便把Fisher's exact test的結果跑出來,使用者不需再去重新執行PROC FREQ一次。
2010年7月23日 星期五
Dropping Automatically Variables with Only Missing Values
Link: http://support.sas.com/resources/papers/proceedings10/048-2010.pdf
在進行資料分析前,有些人會習慣把一些含有missing data的樣本給清除掉,雖然這不會影響到分析結果,因為大部分的SAS程序都是用CCA(Complete Case Analysis)來處理含有missing data的數據,不過若要用手動的方法來清掉missing data的話,在遇到龐大數量的變數時,需要消耗很多時間在輸入遍數名稱上。美國人口普查局的Selvaratnam Sridharma發表了一個macro程序於SAS Global Forum 2010,讓這個程式撰寫的過程只需要幾秒鐘的時間就可以完成。
在進行資料分析前,有些人會習慣把一些含有missing data的樣本給清除掉,雖然這不會影響到分析結果,因為大部分的SAS程序都是用CCA(Complete Case Analysis)來處理含有missing data的數據,不過若要用手動的方法來清掉missing data的話,在遇到龐大數量的變數時,需要消耗很多時間在輸入遍數名稱上。美國人口普查局的Selvaratnam Sridharma發表了一個macro程序於SAS Global Forum 2010,讓這個程式撰寫的過程只需要幾秒鐘的時間就可以完成。
2010年3月26日 星期五
PROC MIXED: Macro to assess fixed and random effects for significance using the Likelihood Ratio test and the approximate Mixture Method
原文載點:http://analytics.ncsu.edu/sesug/2009/SC013.Bardenheier.pdf
若要從兩個nested mixed model挑選較佳的模式,比較專業的人會推薦使用Likelihood Ratio Test(以下簡稱LRT)來處理這類的問題。PROC MIXED程序並沒有語法來進行這個檢定,但這個檢定需要使用到的參數,卻全部都可以從PROC MIXED程序的輸出報表內找到。懂得運作的使用者可以從報表拿擷取相關參數,然後自己算一算再查個表大概就知道結果了。我自己曾經在準備博士班資格考時寫了一個簡易的macro來做LRT,但沒想到真的有人把這個觀念發表出來。我稍微看了一下這份技術文件內的macro寫法,與我當年寫的大同小異,但作者有將輸出報表格式設計的比較好看一點,所以我就來介紹一下這個方便進行LRT的macro。
若要從兩個nested mixed model挑選較佳的模式,比較專業的人會推薦使用Likelihood Ratio Test(以下簡稱LRT)來處理這類的問題。PROC MIXED程序並沒有語法來進行這個檢定,但這個檢定需要使用到的參數,卻全部都可以從PROC MIXED程序的輸出報表內找到。懂得運作的使用者可以從報表拿擷取相關參數,然後自己算一算再查個表大概就知道結果了。我自己曾經在準備博士班資格考時寫了一個簡易的macro來做LRT,但沒想到真的有人把這個觀念發表出來。我稍微看了一下這份技術文件內的macro寫法,與我當年寫的大同小異,但作者有將輸出報表格式設計的比較好看一點,所以我就來介紹一下這個方便進行LRT的macro。
2010年3月21日 星期日
A Macro for Computing the Mantel-Fleisś Criterion
原文載點:http://analytics.ncsu.edu/sesug/2009/PO008.Welch.pdf
在作2乘2的卡方分析時,我們通常會看每一格裡面的樣本期望值是不是大於五,如果不大於五的比例超過一半的話,便需要使用 Fisher's exact test 的結果來取代原本的卡方分析結果。但這種判斷方法,在2乘2乘H的表格下並不適用。Mantel 和 Fleisś 在 1980 年代發明了一種判斷方法來專門處理這種情況,不過這個方法並沒有內建在 SAS 現存的程序內,因此 Brandon Welch, Jane Eslinger 和 Rob Woolson 在 2009 年的 SESUG 發表了一篇技術文件,提供一個簡便的 macro 供使用者使用。
在作2乘2的卡方分析時,我們通常會看每一格裡面的樣本期望值是不是大於五,如果不大於五的比例超過一半的話,便需要使用 Fisher's exact test 的結果來取代原本的卡方分析結果。但這種判斷方法,在2乘2乘H的表格下並不適用。Mantel 和 Fleisś 在 1980 年代發明了一種判斷方法來專門處理這種情況,不過這個方法並沒有內建在 SAS 現存的程序內,因此 Brandon Welch, Jane Eslinger 和 Rob Woolson 在 2009 年的 SESUG 發表了一篇技術文件,提供一個簡便的 macro 供使用者使用。
2009年6月18日 星期四
Examining Mediator and Moderator effect using Rural Women HIV Study
原文載點:http://support.sas.com/resources/papers/proceedings09/191-2009.pdf
這一篇技術文件是簡單地利用一個真正的女性HIV資料來教如何使用 SAS 檢定 mediator(或稱 mediation) 和 moderator。關於 mediator 和 moderator 的定義請參照:
Mediator:http://davidakenny.net/cm/mediate.htm
Moderator:http://davidakenny.net/cm/moderation.htm
首先,這個資料背景是來自一個cross-sectional的長期研究裡面所抽出來的第一次面訪資料,總計有 280 位遭到 HIV 感染的女性。
這一篇技術文件是簡單地利用一個真正的女性HIV資料來教如何使用 SAS 檢定 mediator(或稱 mediation) 和 moderator。關於 mediator 和 moderator 的定義請參照:
Mediator:http://davidakenny.net/cm/mediate.htm
Moderator:http://davidakenny.net/cm/moderation.htm
首先,這個資料背景是來自一個cross-sectional的長期研究裡面所抽出來的第一次面訪資料,總計有 280 位遭到 HIV 感染的女性。
2008年10月23日 星期四
Performing Iterative Processes with the Macro Facility
原文載點:http://www.nesug.info/Proceedings/nesug07/cc/cc21.pdf
有時候要針對一組資料裡面不同類別的觀測值進行分析,在所有的 PROC 程序裡面都可以利用 BY 這個語法來完成。但是 BY 並沒有辦法在某些特殊情況下使用,因此利用 macro 進行遞迴式的處理就變成一另一種可行的方式。Katie Joseph 和 Taylor Lewis 在 NESUG 2007 發表了一篇利用 macro + do loop + %scan 來完成 BY 所無法完成的工作,可供有需要的人參考。
有時候要針對一組資料裡面不同類別的觀測值進行分析,在所有的 PROC 程序裡面都可以利用 BY 這個語法來完成。但是 BY 並沒有辦法在某些特殊情況下使用,因此利用 macro 進行遞迴式的處理就變成一另一種可行的方式。Katie Joseph 和 Taylor Lewis 在 NESUG 2007 發表了一篇利用 macro + do loop + %scan 來完成 BY 所無法完成的工作,可供有需要的人參考。
2008年10月21日 星期二
A macro for nearest neighbor imputation
原文載點:http://www.mediafire.com/?sharekey=00ab0205b2465593dd8b33b5aa27078d
長期以來 SAS 內部只能使用 PROC MI 來執行多重插補法的資料插補動作,而當然世界上不可能只有這麼一種方法。由於多重插補法的使用時機需要配合他強大的假定,所以一旦資料不適用 PROC MI 時,SAS 使用者往往沒有別的替代方案。另外,有時缺失值的情況不嚴重,但使用 Complete Case Analysis 直接刪除有缺失值的觀測值,往往對其他沒有缺失值的變數造成一些資料上的浪費。使用 PROC MI 又需要驗證許多假定,還得在事後進行 PROC MIANALYSIS,實在相當浪費時間。如果有個簡單但又不失可靠的替代方案,將可大大增加處理缺失值的效率。Nearest neighbor imputation(以下簡稱 NNI)是個形之多年的資料插補法,但 SAS 現存的程序並不支援。這篇於 SESUG 2008 由 Lung-Chang Chien (我本人)和 Mark Weaver (我的committee member)所發表的技術文件,提供了一個簡易的 macro 來執行 NNI 的插補動作。
長期以來 SAS 內部只能使用 PROC MI 來執行多重插補法的資料插補動作,而當然世界上不可能只有這麼一種方法。由於多重插補法的使用時機需要配合他強大的假定,所以一旦資料不適用 PROC MI 時,SAS 使用者往往沒有別的替代方案。另外,有時缺失值的情況不嚴重,但使用 Complete Case Analysis 直接刪除有缺失值的觀測值,往往對其他沒有缺失值的變數造成一些資料上的浪費。使用 PROC MI 又需要驗證許多假定,還得在事後進行 PROC MIANALYSIS,實在相當浪費時間。如果有個簡單但又不失可靠的替代方案,將可大大增加處理缺失值的效率。Nearest neighbor imputation(以下簡稱 NNI)是個形之多年的資料插補法,但 SAS 現存的程序並不支援。這篇於 SESUG 2008 由 Lung-Chang Chien (我本人)和 Mark Weaver (我的committee member)所發表的技術文件,提供了一個簡易的 macro 來執行 NNI 的插補動作。
2008年9月11日 星期四
Names, Names, Names - Make Me a List
原文載點:http://www2.sas.com/proceedings/forum2007/052-2007.pdf
如果你曾經讀過去年的這一篇文章「Text Utility Macros for Manipulating Lists of Variable Names」,而且也親自使用過該原文作者所提供的 text utility macro 的話,想必一定會對其強大的批次 rename 功能印象深刻。不過這個 macro 有個缺點,那就是在使用前要先定義這個東西:
這個 %let 的作用是把所有原始變數集中定義成 orig_vars 這個變數,然後再讓 text utility 來使用。不過,如果當變數很多時,我們需要手動去輸入,仍舊是相當耗時。而之前我曾經發過這篇文章「Automatically Renaming Common Variables Before Merging」,裡面是利用 PROC SQL 來抓出舊變數名稱。不過,如果舊變數名稱是有規則可尋,比方說 y1~y1000 時( %let 不允許使用 y1-y1000 這種寫法),則這篇在 SAS Global Forum 2007 由 Ian Whitlock 發表的技術文件可以有很大的幫助。
這篇技術文件一共發佈了五個有用的 macro 讓使用者可以輕易操作大量變數名稱。以下就一一介紹:
。%ZIP
這個 macro 顧名思義就和壓縮檔 zip 一樣,可以組合數個不同的變數或 index 來產生有規則的變數。語法如下:
變數解釋如下:
。l1= 第一列字串
。lv1= 取代第一列字串的字串(可省略不用)
。sep1= 用來區隔第一列字串的字元,預設值是空白(%str())
。l2= 第二列字串
。lv2= 取代第二列字串的字串(可省略不用)
。sep2= 用來區隔第二列字串的字元,預設值是空白(%str())
。osep= 用來區隔輸出字串的字元,預設值是空白(%str())
比方說想要生成「Ax By Cz」這三個字串,可使用下列程式:
l1 所表示的「A B C」會去抓在 l2 相對應位置的「x y z」,這便是 %zip 所呈現的功能。
。XPROD
這是可以拿來產生連續字尾或字首的 macro。語法如下:
使用方式和 %zip 一模一樣,但產生出來的效果完全不同。比方說想要產生「lib.w1 lib.w2 lib.w3」這三個字串,可發現這三個字串只有尾數不同,所以可以用 %xprod 來產生:
換句話說,在 %xprod 裡面,l1 是拿來放共同字串,l2 是拿來放會改變的字串。他甚至可以做出更複雜的效果。假設想要產生「a_x a_y b_x b_y c_x c_y」這六個字串,我們可以想像這是一個 3X2 的矩陣:
而實際上 %xprod 就是用這種原理去做字串合併,因此我們只需要輸入:
就可自動產生那六個字串出來。
。RANGE
這是拿來生成連續數字的程式。語法如下:
變數解釋:
。to= 連續數字最後一位數,預設值是 1
。from= 連續數字的第一位數,預設值是 1
。step= 跳號的間格數,預設值是 1
。sep= 分隔連續數字的字元,預設值是空格(%str( ))
顧名思義,如果要生出「1 2 3 4 5」這串連續數字,則可使用:
。REPLACE
這是拿來取代字元的 macro,特別是使用在重新命名的動作裡面。語法如下:
變數解釋:
。l= 輸入字串
。lv= 取代上列字串的字串(可省略不用)
。code= 包含 key 所代表的符號變數的字串,通常是在程式中不會被變動的字串
。key= 用來當作取代「l」代表的字串的符號變數,預設值是 #
。lsep= 用來區隔輸入字串的字元,預設值是空白(%str())
。osep= 用來區隔輸出字串的字元,預設值是空白(%str())
舉例來說,如果在套入一組資料時要順便改變某些變數名稱,則程式碼為:
則可使用 %replace 來簡化:
這個程式會先把 l 所定義的 x y z 用依序一個 # 來取代,而 code 的作用就是把 x y z 一一套入「#=__#」的框架裡面,進而產生「x=__x y=__y z=__z」這三個字串出來。
另外還有更進階的寫法,就是把 %replace 放進另一個自創的 %rename 裡面,程式如下:
%rename 的第一個參數就等於 %replace 的第一個參數,而 pref 就等於輸出字串裡面共有的字串(此例預設值是「__」)。因此原來的程式可以更簡化為:
這時「x y z」就等於「list」,也等於「l」,而 pref 所表示的「__」被丟進 %replace 的 code 參數裡面,則 code 就變成「code= #=__#」,這就便回原來只用 %replace 的那個程式碼了。
%replace 也可以使用在變數轉換上面。比方說上面這個例子,在 rename 後要把新變數轉換成 best 32. 的格式。如果不用額外的 macro 則語法是:
同樣地,我們可以另外自製一個命為 %CHAR2NUM 的 macro,然後套用 %replace 去寫。方法如下:
這個新 macro 的參數用法和 %rename 一樣,但我們來看看 %replace 在裡面發會什麼功用。l 去呼叫 list 所定義的字串,而 code 生出「#=input(&pref#,best32.);」,其中 # 就是暫時替代 l/list 參數所定義的字串,pref 是利用預設值「__」,則 code 其實就是產生下面這三行:
因此原本的程式可以改寫成:
。QT
這個 macro 只是很簡單地幫每個字元加上雙引號。語法如下:
變數解釋:
。l= 輸入字串
。lv= 取代上列字串的字串(可省略不用)
。lsep= 用來區隔輸入字串的字元,預設值是空白(%str())
。qt= 幫每個字元左右加上的符號,預設值是雙引號(")
。osep= 用來區隔輸出字串的字元,預設值是空白(%str())
因此,如果要生成出「"a" "b" "c"」只需要簡單地使用:
以下是各 macro 的原始碼:
。ZIP
。XPROD
%RANGE
。REPLACE
Contact information
Ian Whitlock
29 Lonsdale Lane
Kennett Square, PA 19348
Ian.Whitlock@comcast.net
如果你曾經讀過去年的這一篇文章「Text Utility Macros for Manipulating Lists of Variable Names」,而且也親自使用過該原文作者所提供的 text utility macro 的話,想必一定會對其強大的批次 rename 功能印象深刻。不過這個 macro 有個缺點,那就是在使用前要先定義這個東西:
%let orig_vars = a01a a01b d01 d02 t1_r t2_r;
這個 %let 的作用是把所有原始變數集中定義成 orig_vars 這個變數,然後再讓 text utility 來使用。不過,如果當變數很多時,我們需要手動去輸入,仍舊是相當耗時。而之前我曾經發過這篇文章「Automatically Renaming Common Variables Before Merging」,裡面是利用 PROC SQL 來抓出舊變數名稱。不過,如果舊變數名稱是有規則可尋,比方說 y1~y1000 時( %let 不允許使用 y1-y1000 這種寫法),則這篇在 SAS Global Forum 2007 由 Ian Whitlock 發表的技術文件可以有很大的幫助。
這篇技術文件一共發佈了五個有用的 macro 讓使用者可以輕易操作大量變數名稱。以下就一一介紹:
。%ZIP
這個 macro 顧名思義就和壓縮檔 zip 一樣,可以組合數個不同的變數或 index 來產生有規則的變數。語法如下:
%zip (l1= , lv1= , sep1=, l2= , lv2= , sep2= , osep= )
變數解釋如下:
。l1= 第一列字串
。lv1= 取代第一列字串的字串(可省略不用)
。sep1= 用來區隔第一列字串的字元,預設值是空白(%str())
。l2= 第二列字串
。lv2= 取代第二列字串的字串(可省略不用)
。sep2= 用來區隔第二列字串的字元,預設值是空白(%str())
。osep= 用來區隔輸出字串的字元,預設值是空白(%str())
比方說想要生成「Ax By Cz」這三個字串,可使用下列程式:
%zip(l1=A B C, l2=x y z);
l1 所表示的「A B C」會去抓在 l2 相對應位置的「x y z」,這便是 %zip 所呈現的功能。
。XPROD
這是可以拿來產生連續字尾或字首的 macro。語法如下:
%xprod ( l1= , lv1= , l2= , lv2=, sep1=, sep2=, osep=) )
使用方式和 %zip 一模一樣,但產生出來的效果完全不同。比方說想要產生「lib.w1 lib.w2 lib.w3」這三個字串,可發現這三個字串只有尾數不同,所以可以用 %xprod 來產生:
%xprod(l1=lib.w, l2=1 2 3);
換句話說,在 %xprod 裡面,l1 是拿來放共同字串,l2 是拿來放會改變的字串。他甚至可以做出更複雜的效果。假設想要產生「a_x a_y b_x b_y c_x c_y」這六個字串,我們可以想像這是一個 3X2 的矩陣:
x y
a_
b_
c_
而實際上 %xprod 就是用這種原理去做字串合併,因此我們只需要輸入:
%xprod(l1=a_ b_ c_, l2=x y);
就可自動產生那六個字串出來。
。RANGE
這是拿來生成連續數字的程式。語法如下:
%range ( to=, from= , step= , sep= )
變數解釋:
。to= 連續數字最後一位數,預設值是 1
。from= 連續數字的第一位數,預設值是 1
。step= 跳號的間格數,預設值是 1
。sep= 分隔連續數字的字元,預設值是空格(%str( ))
顧名思義,如果要生出「1 2 3 4 5」這串連續數字,則可使用:
%range(to=5);
。REPLACE
這是拿來取代字元的 macro,特別是使用在重新命名的動作裡面。語法如下:
%replace ( l= , lv= , code= , key= , lsep=, osep=)
變數解釋:
。l= 輸入字串
。lv= 取代上列字串的字串(可省略不用)
。code= 包含 key 所代表的符號變數的字串,通常是在程式中不會被變動的字串
。key= 用來當作取代「l」代表的字串的符號變數,預設值是 #
。lsep= 用來區隔輸入字串的字元,預設值是空白(%str())
。osep= 用來區隔輸出字串的字元,預設值是空白(%str())
舉例來說,如果在套入一組資料時要順便改變某些變數名稱,則程式碼為:
data ww;
set w(rename=(x=__x y=__y z=__z);
run;
則可使用 %replace 來簡化:
data ww;
set w(rename=(%replace(l=x y z, code=#=__#));
run;
這個程式會先把 l 所定義的 x y z 用依序一個 # 來取代,而 code 的作用就是把 x y z 一一套入「#=__#」的框架裡面,進而產生「x=__x y=__y z=__z」這三個字串出來。
另外還有更進階的寫法,就是把 %replace 放進另一個自創的 %rename 裡面,程式如下:
%macro rename ( list, pref=__) ;
%replace ( l=&list, code = # = &pref# )
%mend rename ;
%rename 的第一個參數就等於 %replace 的第一個參數,而 pref 就等於輸出字串裡面共有的字串(此例預設值是「__」)。因此原來的程式可以更簡化為:
data ww;
set w(rename=(%rename(x y z)));
run;
這時「x y z」就等於「list」,也等於「l」,而 pref 所表示的「__」被丟進 %replace 的 code 參數裡面,則 code 就變成「code= #=__#」,這就便回原來只用 %replace 的那個程式碼了。
%replace 也可以使用在變數轉換上面。比方說上面這個例子,在 rename 後要把新變數轉換成 best 32. 的格式。如果不用額外的 macro 則語法是:
data ww;
set w(rename=(%rename(x y z)));
x=input(__x, best32.);
y=input(__y, best32.);
z=input(__z, best32.);
run;
同樣地,我們可以另外自製一個命為 %CHAR2NUM 的 macro,然後套用 %replace 去寫。方法如下:
%macro char2num ( list , pref = __ ) ;
%replace ( l=&list
, code= %str(# = input(&pref#,best32.);)
)
%mend char2num ;
這個新 macro 的參數用法和 %rename 一樣,但我們來看看 %replace 在裡面發會什麼功用。l 去呼叫 list 所定義的字串,而 code 生出「#=input(&pref#,best32.);」,其中 # 就是暫時替代 l/list 參數所定義的字串,pref 是利用預設值「__」,則 code 其實就是產生下面這三行:
x=input(__x, best32.);
y=input(__y, best32.);
z=input(__z, best32.);
因此原本的程式可以改寫成:
data ww;
set w(rename=(%rename(x y z)));
%char2num(x y z);
run;
。QT
這個 macro 只是很簡單地幫每個字元加上雙引號。語法如下:
%qt ( l=, lv= , lsep= %str( ), qt = %str(%"), osep=%str( ) )
變數解釋:
。l= 輸入字串
。lv= 取代上列字串的字串(可省略不用)
。lsep= 用來區隔輸入字串的字元,預設值是空白(%str())
。qt= 幫每個字元左右加上的符號,預設值是雙引號(")
。osep= 用來區隔輸出字串的字元,預設值是空白(%str())
因此,如果要生成出「"a" "b" "c"」只需要簡單地使用:
%qt(l=a b c);
以下是各 macro 的原始碼:
。ZIP
%macro zip
( l1= /* first list */
, lv1= /* external variable override for first list */
, sep1=%str( ) /* separator between the joined elements */
, l2= /* second list */
, lv2= /* external variable override for second list */
, sep2=%str( ) /* separator between the joined elements */
, osep=%str( ) /* separator between new elements */
) ;
/* %zip ( l1= a b , l2= c d ) produces ac bd
so does
%let list1 = a b ;
%let list2 = c d ;
%zip (lv1=list1, lv2=list2)
If lists do not have same length shorter length used and
warning to the log. Empty lists result in empty list and
no message.
If the LV options are used then L1, L2, and ZIP_: should be
avoided for variable names.
*/
%local zip_i zip_1 zip_2 zip_list ;
%if %length(&lv1) = 0 %then
%let lv1 = l1 ;
%if %length(&lv2) = 0 %then
%let lv2 = l2 ;
%do zip_i = 1 %to &sysmaxlong ;
%let zip_1 = %qscan(%superq(&lv1) , &zip_i, &sep1 ) ;
%let zip_2 = %qscan(%superq(&lv2) , &zip_i, &sep2 ) ;
%if %length(&zip_1) = 0 or %length(&zip_2) = 0 %then
%goto check ;
%if &zip_i = 1 %then
%let zip_list = &zip_1&zip_2 ;
%else
%let zip_list = &zip_list&osep&zip_1&zip_2 ;
%end ;
%check:
%if %length(&zip_1) > 0 or %length(&zip_2) > 0 %then
%put WARNING: Macro ZIP - list lengths do not match - shorter used. ;
%unquote(&zip_list)
%mend zip ;
。XPROD
%macro xprod
( l1= /* first list */
, lv1= /* external variable override for first list */
, sep1=%str( ) /* separator between elements of first list */
, l2= /* second list */
, lv2= /* external variable override for second list */
, sep2=%str( ) /* separator between elements of second list */
, osep=%str( ) /* separator between elements of new list */
) ;
%local xp_i xp_j xp_1 xp_2 xp_list ;
%if %length(&lv1) = 0 %then
%let lv1 = l1 ;
%if %length(&lv2) = 0 %then
%let lv2 = l2 ;
%do xp_i = 1 %to &sysmaxlong ;
%let xp_1 = %qscan(%superq(&lv1), &xp_i, &sep1) ;
%if %length(&xp_1) = 0 %then %goto endloop1 ;
%do xp_j = 1 %to &sysmaxlong ;
%let xp_2 = %qscan(%superq(&lv2), &xp_j, &sep2) ;
%if %length(&xp_2) = 0 %then %goto endloop2 ;
%if &xp_i = 1 and &xp_j = 1 %then
%let xp_list = &xp_1&xp_2 ;
%else
%let xp_list = &xp_list&osep&xp_1&xp_2 ;
%end ;
%endloop2:
%end ;
%endloop1:
%unquote(&xp_list)
%mend xprod ;
%RANGE
%macro range /* second more efficient version due to Chang Chung */
( to=1 /* end integer value */
, from=1 /* starting integer value */
, step=1 /* increment integer */
, osep=%str( ) /* sparator between integers */
) ;
/*
return sequence of integers starting at &FROM going to &TO
in steps of &step
%range(to=5) produces 1 2 3 4 5
*/
%local rg_i ;
%do rg_i = &from %to &to %by &step ;
%if &rg_i = &from %then
%do;&rg_i%end ;
%else
%do;&osep&rg_i%end ;
%end ;
%mend range ;
。REPLACE
%macro replace
( l= /* value list */
, lv= /* external variable override for value list */
, lsep=%str( ) /* separator between values */
, code= /* block of code containing symbolic variable */
, key=# /* symbolic variable to replace (#abc# etc.) */
, osep=%str( ) /* separator between new elements */
/* may be %str(;) when code is statement */
/* if so remember to add closing semicolon */
) ;
%local rg_i rg_w rg_list ;
%if %length(&lv) = 0 %then
%let lv = l ;
%if %length(%superq(&lv)) = 0 /*or %index(%superq(code),&key) = 0*/ %then
%do ;
%let rg_list = %superq(code) ;
%goto mexit ;
%end ;
%do rg_i = 1 %to &sysmaxlong ;
%let rg_w = %qscan(%superq(&lv),&rg_i,&lsep) ;
%if %length(&rg_w) = 0 %then %goto mexit ;
%if &rg_i = 1 %then
%let rg_list = %sysfunc(tranwrd(%superq(code),&key,&rg_w)) ;
%else
%let rg_list =
&rg_list&osep%sysfunc(tranwrd(%superq(code),&key,&rg_w)) ;
%end ;
%mexit:
%unquote(&rg_list)
%mend replace ;
Contact information
Ian Whitlock
29 Lonsdale Lane
Kennett Square, PA 19348
Ian.Whitlock@comcast.net
2008年6月23日 星期一
Reliability analysis: Calculate and Compare Intra-class Correlation Coefficients (ICC) in SAS
原文載點:http://www.nesug.info/Proceedings/nesug07/sa/sa13.pdf
在 reliability analysis 裡面,intra-class correlation coefficients (ICC) 是一個相當重要的統計指標。不過長久以來,SAS 內部並沒有可以直接計算 ICC 的程序。雖然有許多線上的 ICC 計算器,不過仍有許多人研發出在 SAS 上運作的 ICC macro 供 SAS 使用者使用。Li Lu 和 Nawar Shara 在 2007 年的 NESUG 發表了一篇自行撰寫的 ICC macro 技術文件,不但可用來計算 ICC 本身,還可以求出其信賴區間。
原始碼如下:
包含三個參數:
由於原文沒有提供 one 這個資料集的原始資料,所以不知道跑出來的結果如何。有興趣的人可以拿自己的資料測試,並與其他線上 ICC 計算器的結果進行比對。如有發現異常現象請回報給原作者。
CONTACT INFORMATION
Your code requests, comments and questions are valued and encouraged. Contact the author at
Li Lu
Dept of Epidemiology and Statistics
MedStar Research Institute
6495 New Hampshire Avenue
Hyattsville, MD 20783
(301) 560-7313
li.lu@medstar.net
在 reliability analysis 裡面,intra-class correlation coefficients (ICC) 是一個相當重要的統計指標。不過長久以來,SAS 內部並沒有可以直接計算 ICC 的程序。雖然有許多線上的 ICC 計算器,不過仍有許多人研發出在 SAS 上運作的 ICC macro 供 SAS 使用者使用。Li Lu 和 Nawar Shara 在 2007 年的 NESUG 發表了一篇自行撰寫的 ICC macro 技術文件,不但可用來計算 ICC 本身,還可以求出其信賴區間。
原始碼如下:
%macro Icc_sas(ds, response, subject);
ods output OverallANOVA =all;
proc glm data=&ds;
class &subject;
model &response=&subject;
run;
data Icc(keep=sb sw n R R_low R_up);
retain sb sw n;
set all end=last;
if source='Model' then sb=ms;
if source='Error' then do;sw=ms; n=df; end;
if last then do;
R=round((sb-sw)/(sb+sw), 0.01);
vR1=((1-R)**2)/2;
vR2=(((1+R)**2)/n +((1-R)*(1+3*R)+4*(R**2))/(n-1));
VR=VR1*VR2;
L=(0.5*log((1+R)/(1-R)))-(1.96*sqrt(VR))/((1+R)*(1-R));
U=(0.5*log((1+R)/(1-R)))+(1.96*sqrt(VR))/((1+R)*(1-R));
R_Low=(exp(2*L)-1)/(exp(2*L)+1);
R_Up=(exp(2*U)-1)/(exp(2*U)+1);
output;
end;
run;
proc print data=icc noobs split='*';
var r r_low r_up;
label r='ICC*' r_low='Lower bound*' r_up='Upper bound*';
title 'Reliability test: ICC and its confidence limits';
run;
%mend;
包含三個參數:
- ds:資料名稱(含 library)
- response:反應變數名稱
- subject:ID 名稱
%Icc_sas(ds=one, response=cimt, subject=subject_id);
由於原文沒有提供 one 這個資料集的原始資料,所以不知道跑出來的結果如何。有興趣的人可以拿自己的資料測試,並與其他線上 ICC 計算器的結果進行比對。如有發現異常現象請回報給原作者。
CONTACT INFORMATION
Your code requests, comments and questions are valued and encouraged. Contact the author at
Li Lu
Dept of Epidemiology and Statistics
MedStar Research Institute
6495 New Hampshire Avenue
Hyattsville, MD 20783
(301) 560-7313
li.lu@medstar.net
訂閱:
文章 (Atom)