2014-09-28 56 views
2

具有像這樣的結構的多個受試者反覆評估用藥的時間序列數據(使用data.table)重疊:的R - 重塑始端的時間間隔,以確定倍

library(data.table) 
dt1 = setDT(structure(list(id = c("G", "G", "G", "G", "M", "M", "M", "M", 
    "M", "M", "M"), med = c("mult", "R", "mult", "R", "A", "mult", 
    "A", "C", "A", "Q", "A"), strt = c(19059L, 19061L, 19065L, 19066L, 
    19136L, 19138L, 19142L, 19142L, 19155L, 19246L, 19257L), end = c(19061L, 
    19065L, 19066L, 19101L, 19138L, 19139L, 19172L, 19172L, 19255L, 
    19276L, 19287L)), .Names = c("id", "med", "strt", "end"), row.names = c(NA, 
    -11L), class = "data.frame")) 

產生data.table dt1

id med strt end 
1: G mult 19059 19061 
2: G R 19061 19065 
3: G mult 19065 19066 
4: G R 19066 19101 
5: M A 19136 19138 
6: M mult 19138 19139 
7: M A 19142 19172 
8: M C 19142 19172 
9: M A 19155 19255 
10: M Q 19246 19276 
11: M A 19257 19287 

我試圖重新組織數據,使得,對於每個受試者,任何一天,患者是在> 1 MED被重構成'mult',和一個給定的藥物治療方案的連續天被表示爲單個行。

因此,期望的結果是dt2

id med strt end 
1: G mult 19059 19061 
2: G R 19062 19064 
3: G mult 19065 19066 
4: G R 19067 19101 
5: M A 19136 19137 
6: M mult 19138 19139 
7: M mult 19142 19172 
8: M A 19173 19245 
9: M mult 19246 19255 
10: M Q 19256 19256 
11: M mult 19257 19276 
12: M A 19277 19287 

我已經寫以下代碼這樣做,但它是緩慢和冗長。有人能幫我改進嗎?

dt2 = dt1[, list(id, med, day=seq(strt,end)), by=1:nrow(dt1)] 
setkey(dt2,'id','day') 
dt2[, med := ifelse(length(unique(med))>1, 'mult', med), by=list(id,day)] 
dt2 = unique(dt2) 
medrun <- function(y,z){ 
    cnt = grp = 1L 
    lx = length(y) 
    ne = y[-lx] != y[-1L] 
    n1 = z[-lx] - z[-1L] != -1 
    for(i in seq_along(ne)){if(ne[i] | n1[i])cnt=cnt+1; grp[i+1]=cnt} 
    grp 
} 
dt2[,grp := as.numeric(medrun(med,day)), by=id] 
setkey(dt2,'id','grp') 
dt2[,strt := min(day), by=list(id,grp)] 
dt2[,end := max(day), by=list(id,grp)] 
dt2 = unique(dt2) 
dt2 = subset(dt2, select = c('id','med','strt','end')) 

數據集很大(> 3M行),所以解決方案需要高效且快速的存儲。理想情況下,不希望將間隔擴展到1 obs/day。

+0

相符的一兩件事,不使用'ifelse'(見http://stackoverflow.com/q/16275149/1492421) - 你'data.table'不需要它'''dt2'上面的'setkey'。最後,在'data.table'上使用'subset'首先會損害'data.table'的大部分重要性。 – 2014-09-28 03:59:58

+0

@RicardoSaporta謝謝。我編輯了一下,稍後會做更多。我有點破了我的解決方案,我知道它有各種低效率。雖然我很欣賞一般的指針(例如,不知道關於'data.table'中的'ifelse'),但我對漸進式改進不感興趣,而不是尋找一種根本不同且更高效的方法,它不需要吹出間隔。 – dnaiel 2014-09-28 04:12:52

回答

1

我會一天擴大,設置鍵,然後相應地

DT_meds <- DT1[, list(day = if (.N ==1) seq(from=strt, to=end) else unlist(mapply(seq, strt, end))), keyby=list(id, med)] 
setkey(DT_meds, id, day, med) 
DT_meds[, med := if (length(unique(med)) > 1) "mult" else med, by=list(id, day)] 
DT_meds[, grp := cumsum (c(FALSE, diff(day) > 1)), by=list(id, med) ] 

DT_results <- DT_meds[, list(str=day[1L], end=day[.N]), by=list(id, med, grp)] 
DT_results[, grp := NULL] 

DT_results 
#  id med str end 
# 1: G mult 19059 19061 
# 2: G R 19062 19064 
# 3: G mult 19065 19066 
# 4: G R 19067 19101 
# 5: M A 19136 19137 
# 6: M mult 19138 19139 
# 7: M mult 19142 19172 
# 8: M A 19173 19245 
# 9: M mult 19246 19255 
# 10: M Q 19256 19256 
# 11: M mult 19257 19276 
# 12: M A 19277 19287 
+0

不運行。我認爲'kCols'需要被定義? – dnaiel 2014-09-29 01:20:44

+0

將'kCols'更改爲'list(id,med)'後它正確運行,所以我編輯了你的答案來解決這個問題。我upvoted,但將保持現在的問題,希望得到一個不需要白天擴大的答案。 – dnaiel 2014-09-29 01:34:19