一、在data步中完成
proc sort data=LB_SDTM1;by SUBJID LBCAT LBTESTCD descending LBDTCN descending LBDTC;run;
data LB_QSDTM;
set LB_SDTM1;
by SUBJID LBCAT LBTESTCD descending LBDTCN;
if LBSTAT^='NOT DONE' then do;
????LBDYlg=lag(LBDY);
????SUBJIDlg=lag(SUBJID);
????LBCATlg=lag(LBCAT);
????LBTESTCDlg=lag(LBTESTCD);
end;
if . < LBDY <= 1 and (LBDYlg>1 or SUBJID ne SUBJIDlg or LBCAT ne LBCATlg or LBTESTCD ne LBTESTCDlg) and LBSTAT^='NOT DONE' then LBBLFL='Y';
run;
????????首先是排序,排序一定是按照時(shí)間倒敘排列,因?yàn)榛€的制作是要保證2個(gè)條件,一個(gè)是早于首次用藥,這個(gè)很好判斷。另一個(gè)是要在時(shí)間上距離首次用藥最近,這個(gè)如果在正序的前提下很難得到,因?yàn)閟as沒法預(yù)判下一條(下一個(gè)時(shí)間點(diǎn))是不是也在首次用藥之前,這樣就沒法判斷當(dāng)前的觀測是不是距離最近的了。
? ? ? ? 一般在SDTM中DY變量會指示具體首次用藥的日期差值,我們可以直接使用這個(gè)變量,如果條件不允許可以自己制作,無論是日期差還是時(shí)間差都是可以的。這里使用的是LBDY,因?yàn)槿绻掌谙嗟?,DY變量會+1,所以是小于等于1作為判斷是否早于給藥時(shí)間的條件。而LBDYlg這個(gè)變量是上一條中的LBDY,LBDYlg > 1 是為了保證當(dāng)前一條是距離給藥時(shí)間最近的一條。因?yàn)槲覀儠r(shí)間是倒序的,所以上一條是下一個(gè)時(shí)間點(diǎn),下一個(gè)時(shí)間點(diǎn)晚于給藥時(shí)間,本條早于給藥時(shí)間才能滿足條件。
????????LBDYlg>1 后面跟了一大串?SUBJID ne SUBJIDlg or LBCAT ne LBCATlg or LBTESTCD ne LBTESTCDlg 。這些條件是為了防止出現(xiàn)下面情況:本條的時(shí)間點(diǎn)是給藥前,并且是當(dāng)前參數(shù)下的最后一個(gè)時(shí)間點(diǎn)。此時(shí)本條應(yīng)該被標(biāo)記為基線,但如果沒有這一大串代碼,是無法實(shí)現(xiàn)標(biāo)記基線的。具體原因如下:我們是希望以每 SUBJID LBCAT LBTESTCD(這個(gè)組合當(dāng)然要根據(jù)需要調(diào)整) 的一個(gè)值得組合,作為一個(gè)單獨(dú)的考察基線的分組。所以我們會按SUBJID LBCAT LBTESTCD排序,這樣,如果本條和上一條相比,無論這三個(gè)變量中的哪一個(gè)發(fā)生變化,就說明本條已經(jīng)是一個(gè)新的分組了。別忘記我們是按時(shí)間倒序排序的,換句話說此時(shí)當(dāng)前分組的最晚的一條依然要早于給藥時(shí)間。既然已經(jīng)是最后一條,那麼就只能加上基線標(biāo)記了(當(dāng)然這是可以根據(jù)實(shí)際需要調(diào)整的)。
? ? ? ? 同時(shí),條件中還有一個(gè)?LBSTAT^='NOT DONE' 這個(gè)很顯然,未作的行不能做為基線。但是需要解釋的是為什么不能在最后的賦值LBBLFL的if語句中直接使用lag函數(shù),而是要事先復(fù)制,以及賦值的時(shí)候?yàn)槭裁匆訔l件。
? ? ? ? 以上的所有關(guān)于LBDYlg,SUBJIDlg,LBCATlg,LBTESTCDlg 的分析中,都隱含著一個(gè)前提,就是上一行必須不能是 LBSTAT='NOT DONE' 的。如何保證上一行肯定不是未做呢?這就涉及到 lag 函數(shù)的特點(diǎn):嚴(yán)格來說 lag 函數(shù)并不是返回變量上一行的值,而是返回 lag 函數(shù) 上一次起作用時(shí),那個(gè)變量的值。
????????所以我們不能在最后的賦值LBBLFL的if語句中直接使用lag函數(shù),因?yàn)槊恳恍卸紩?zhí)行從 if 到 then 中間的部分,所以如果寫成 :
if . < LBDY <= 1 and (
lag?(LBDY)>1 or?
SUBJID ne lag?(SUBJID) or?
LBCAT ne lag?(LBCAT) or?
LBTESTCD ne lag?(LBTESTCD)
) and LBSTAT^='NOT DONE' then LBBLFL='Y';
則lag 函數(shù)返回的永遠(yuǎn)是上一行,而上一行是無法確保一定不是 LBSTAT='NOT DONE'? 的。而如果我們在前面事先賦值,而且放在條件語句then的后面:
if LBSTAT^='NOT DONE' then do;
????LBDYlg=lag(LBDY);
????SUBJIDlg=lag(SUBJID);
????LBCATlg=lag(LBCAT);
????LBTESTCDlg=lag(LBTESTCD);
end;
則 lag 函數(shù)上一次起作用的值,永遠(yuǎn)是符合LBSTAT^='NOT DONE'的觀測,因此它返回的一定是上一次LBSTAT^='NOT DONE' 的觀測值,這樣就可以完美跳過未做行。
? ? ? ? 這也是為什么不使用first和last方法而使用lag來確定分組的原因,因?yàn)槭褂胒irst或last,最終也是無法判斷是否未做。最后這個(gè)語句還有一個(gè)好處,就是它可以嵌入到其他data步當(dāng)中,只要事先排序,不需要使用by語句,所以不會收到merge是by語句的限制。
如果需要做基線后的話可以加上:
proc sort data=LB_SDTM1;by SUBJID LBCAT LBTESTCD descending LBDTCN descending LBDTC;run;
data LB_QSDTM;
set LB_SDTM1;
by SUBJID LBCAT LBTESTCD descending LBDTCN;
retain LBPOBLFL ;
if LBSTAT^='NOT DONE' then do;
????LBDYlg=lag(LBDY);
????SUBJIDlg=lag(SUBJID);
????LBCATlg=lag(LBCAT);
????LBTESTCDlg=lag(LBTESTCD);
end;
if . < LBDY <= 1 and (LBDYlg>1 or SUBJID ne SUBJIDlg or LBCAT ne LBCATlg or LBTESTCD ne LBTESTCDlg) and LBSTAT^='NOT DONE' then LBBLFL='Y';
if (SUBJID ne SUBJIDlg or LBCAT ne LBCATlg or LBTESTCD ne LBTESTCDlg) then LBPOBLFL='Y';?
if ?LBBLFL='Y' then LBPOBLFL='';
run;
當(dāng)然,這樣需要在后續(xù)的data步中,去掉未做行的標(biāo)記。