公告

[公告]
2014/01/17
由於已經是faculty的關係,不太有足夠時間寫部落格。因此更新的速度會相當緩慢。再加上近幾年來SAS GLOBAL FORUM沒有出現讓我覺得驚艷的技術文件,所以能分享的文章相對也減少許多。若有人推薦值得分享的SAS技術文件,請利用『問題討論區』告知。

2013/07/19
臉書留言板的功能因為有不明原因故障,因此特此移除。而intensedebate的留言板因管理不易,也一併移除。目前已經開啟內建的 G+ 留言系統,所以請有需要留言的朋友,可直接至『問題討論區』裡面留言。


2007年3月4日 星期日

Identifying Continuity in Longitudinal Data

原文載點:http://www2.sas.com/proceedings/sugi28/089-28.pdf

這一篇由 Merle E. Hamburger 和 Thomas Sukalac 二人一同於 2003 年的 SUGI 28 所發表的文章,主要是針對在分析長期趨勢資料時所經常會碰到的一個問題,即觀測值是否在實驗期間不間斷地都有觀測到數據或是長期間連續地暴露在某一種狀態下。也就是說,我們所關心的,是倒底這段不中斷的時間到底持續了多久。兩人寫了一段 SAS 程式,來說明如何從原始資料得到這種數據。

兩人使用一個有關 HIV 感染者的世代研究資料來當作範例。此資料包含下列變數:

HRNID = study ID
VLOAD = HIV viral load
VBDATE = date of viral load assessment

首先,利用 PROC SORT 將資料 依照 HRHID 變數排序。

proc sort data=VLDATA ;
by hrnid ;
run ;


接下來就是使用一個 Data procedure 把每個病人從一開始到 viral load 成功的時間算出來。我將這個程式拆成數段分別解釋。

data INTERVAL ;
set VLDATA ;
by hrnid ;
retain inint begdate enddate ;
keep hrnid begdate enddate interval undetect ;


建立一個新的資料集名為 INTERVAL,除了引用原始資料 VLDATA 外,retain 可以使變數在經過任何迴圈或條件式之後,在下一次進入迴圈或條件式前仍能繼續保有數值。若沒有 retain 的話,所有的變數在一進入 Data procedure 時都會被視為 missing。By hrnid 是希望舊的資料能夠依照 hrnid 的順序讀進,並順便讓 SAS 產生兩個隱藏的變數:first.hrnid 和 last.hrnid。當該筆資料是某個病人的第一個觀測值,則其 first.hrnid = 1,反之為 0。 同道理,若該筆資料是某個病人的最後一個觀測值,則 last.hrnid = 1,反之為 0。這個程序會生出一些新的變數,如 begdate, enddate, interval (最重要的)和 undetect。連同 hrnid ,將會被 keep 指令給繼續留在新的資料集當中。

接著,新增一個 inint 的變數,且讓他在 first.hrnid =1 時為零。

if first.hrnid then inint = 0 ;

再來,設定兩個條件子 inint = 0 和 vload = 1,產生一個新變數 begdate,使的滿足這兩個條件的病人的 begdate 值等於 vbdate,並讓其 inint 值改變為 1。

if (inint = 0) and (vload = 1) then do ;
begdate = vbdate ;
inint = 1 ;
end ;


完成上述動作後,新增一個 enddate 變數,使其在滿足 inint = 1 時,其值會等於 vbdate。

if inint = 1 then enddate = vbdate ;

接著,當滿足兩個條件子 inint = 1 和 vload > 1 時,先讓 inint 歸零,再來就是要算時間區間 interval 了(除以 365.25 以轉換其單位成年)。但若 interval 大於二,則新增一個變數 undetect 並使其為 1。

if inint = 1 and vload > 1 then do ;
inint = 0;
interval = (enddate - begdate) / 365.25 ;
if interval ge 2 then do ;
undetect = 1 ;
output;
end ;
end ;


下面的程式功能和上面那個一樣,唯一不同的是考量當 last.hrnid = 1 時該怎樣去算 interval。

if last.hrnid and inint = 1 then do ;
interval = (enddate - begdate) / 365.25 ;
if interval ge 2 then do ;
undetect = 1 ;
output;
end ;
end ;


最後利用 format 語法將算出來的 begdate 和 enddate 轉換成「月/日/年」的時間型態,而 interval 則轉成 4.2 格式型態。

format begdate mmddyy10. enddate mmddyy10. interval 4.2 ;

如此一來就大功告成了!!

完整程式:

data INTERVAL ;
set VLDATA ;
by hrnid ;
retain inint begdate enddate ;
keep hrnid begdate enddate interval undetect ;
if first.hrnid then inint = 0 ;
if (inint = 0) and (vload = 1) then do ;
begdate = vbdate ;
inint = 1 ;
end ;
if inint = 1 then enddate = vbdate ;
if inint = 1 and vload > 1 then do ;
inint = 0;
interval = (enddate - begdate) / 365.25 ;
if interval ge 2 then do ;
undetect = 1 ;
output;
end ;
end ;
if last.hrnid and inint = 1 then do ;
interval = (enddate - begdate) / 365.25 ;
if interval ge 2 then do ;
undetect = 1 ;
output;
end ;
end ;
format begdate mmddyy10. enddate mmddyy10. interval 4.2 ;
run ;


CONTACT INFORMATION
Your comments and questions are valued and encouraged.
Contact the author at:
Merle E. Hamburger
CDC-P
1600 Clifton Rd., MS E-45
Atlanta, GA 30333
(404) 639-5263
(404) 639-6127 (fax)
mhamburger@cdc.gov

沒有留言:

張貼留言

要問問題的人請在文章下方的intensedebate欄位留言,請勿使用blogger預設的意見表單。今後用blogger意見表單留言的人我就不回應了。

CODE { display: block; /* fixes a strange ie margin bug */ font-family: Courier New; font-size: 8pt; overflow:auto; background: #f0f0f0 url(http://klcintw.images.googlepages.com/Code_BG.gif) left top repeat-y; border: 1px solid #ccc; padding: 10px 10px 10px 21px; max-height:200px; height:200px; // for IE6 line-height: 1.2em; }