2012-12-30 35 views
2

我有一個長格式的巨大數據文件 - 下面提供了它的一部分。每個ID可以有多行,其中狀態是最終狀態。不過,我需要用時變協變量來進行分析,因此需要創建兩個新的時間變量並更新狀態變量。我一直在爲此掙扎一段時間,我無法弄清楚如何有效地做到這一點,因爲每個ID最多可以有四行。時變變量是NUM.AFTER.DIAG。如果NUM.AFTER.DIAG==0那麼很容易,其中time1=0time2=STATUSDATE。然而,當NUM.AFTER.DIAG==1然後我需要做一個新的行,其中time1=0,time2=DOB-DATE.DIAGNUM.AFTER.DIAG=0並且還確保STATUS="B"。第二行然後是來自該行的前一行time1=time2和來自該行的time2=STATUSDATE-DATE.DIAG-time1。同樣,如果有更多的行,那麼不同的行需要相互減去。另外,如果NUM.AFTER.DIAG == 0但有多行,則可以刪除所有額外的行。用於在r中創建時變協變量的工作流程

有效解決此問題的任何想法? 我看過約翰福克斯展開命令,但它假定所有的時間間隔都是以寬格式開始的。

編輯:根據要求的表格。至於御史變量:「d」 =事件(死亡)

enter image description here

structure(list(ID = c(187L, 258L, 265L, 278L, 281L, 281L, 283L, 
    283L, 284L, 291L, 292L, 292L, 297L, 299L, 305L, 305L, 311L, 311L, 
    319L, 319L, 319L, 322L, 322L, 329L, 329L, 333L, 333L, 333L, 334L, 
    334L), STATUS = c("D", "B", "B", "B", "B", "B", "D", "D", "B", 
    "B", "B", "B", "D", "D", "D", "D", "B", "B", "B", "B", "B", "D", 
    "D", "B", "B", "D", "D", "D", "D", "D"), STATUSDATE = structure(c(11153, 
    15034, 15034, 15034, 15034, 15034, 5005, 5005, 15034, 15034, 
    15034, 15034, 6374, 5005, 7562, 7562, 15034, 15034, 15034, 15034, 
    15034, 7743, 7743, 15034, 15034, 4670, 4670, 4670, 5218, 5218 
    ), class = "Date"), DATE.DIAG = structure(c(4578, 4609, 4578, 
    4487, 4670, 4670, 4517, 4517, 4640, 4213, 4397, 4397, 4397, 4487, 
    4213, 4213, 4731, 4731, 4701, 4701, 4701, 4397, 4397, 4578, 4578, 
    4275, 4275, 4275, 4456, 4456), class = "Date"), DOB = structure(c(NA, 
    13010, NA, NA, -1082, -626, 73, 1353, 13679, NA, 1626, 3087, 
    -626, -200, 2814, 3757, 1930, 3787, 6740, 13528, 14167, 5462, 
    6557, 7865, 9235, -901, -504, -108, -535, -78), class = "Date"), 
     NUM.AFTER.DIAG = c(0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 1, 2, 3, 1, 2, 1, 2, 0, 0, 0, 0, 0)), .Names = c("ID", 
    "STATUS", "STATUSDATE", "DATE.DIAG", "DOB", "NUM.AFTER.DIAG"), row.names = c(NA, 
    30L), class = "data.frame") 

編輯:我沒有拿出一個解決方案,雖然可能不是很有效。

u1<-ddply(p,.(ID),function(x) { 

    if (x$NUM.AFTER.DIAG==0){ 

    x$time1<-0 
    x$time2<-x$STATUSDATE-x$DATE.DIAG 
    x<-x[1,] 

    } 
    else { 

     x<-rbind(x,x[1,]) 
     x<-x[order(x$DOB),] 
     u<-max(x$NUM.AFTER.DIAG) 
     x$NUM.AFTER.DIAG<-0:u 
     x$time1[1]<-0 
     x$time2[1:(u)]<-x$DOB[2:(u+1)]-x$DATE.DIAG[2:(u+1)] 
     x$time2[u+1]<-x$STATUSDATE[u]-x$DATE.DIAG[u] 
     x$time1[2:(u+1)]<-x$time2[1:u] 
     x$STATUS[1:u]<-"B" 
     } 
    x 
} 
) 
+0

你能否提供一個例子(以表格的形式)說明你的數據在轉換之後的樣子應該是什麼樣子,比方說ID 258,299,319和333?你的STATUS變量指示了什麼? 'B' =事件,'D' =審查? – adibender

+0

您是否已經有解決方案並希望使其更有效率,或者您是否知道如何針對每個人分別執行此操作,但是難以將其應用於所有個人? - 感謝編輯btw – adibender

+1

我確實找到了一個解決方案,剛纔使用plyr和rbind來添加所需的額外列......我將它添加並留給某人找到更有效的方法.. – Misha

回答

0

好吧,我試過的東西,但我不知道我理解你的轉化過程完全,所以讓我知道,如果有一些失誤。一般來說ddply將是緩慢的(即使.parallel = TRUE),當有許多人,因爲它具有月底主要把所有個人的所有數據集一起rbind(或rbind.fill)他們,這永遠花費的大量data.frame對象。

所以這裏有一個建議,其中dat.orig是你的玩具的數據集:

我會先被分割在兩個任務:))看來 1)NUM.AFTER.DIAG == 0

1,如果NUM.AFTER.DIAG == 0,除了計算TIME2並且如果發生一次以上的ID提取第一行的(如ID 333),沒有太多的在第1部分做):

## erase multiple occurences 
dat <- dat.orig[!(duplicated(dat.orig$ID) & dat.orig$NUM.AFTER.DIAG == 0), ] 
dat0 <- dat[dat$NUM.AFTER.DIAG == 0, ] 
dat0$time1 <- 0 
dat0$time2 <- difftime(dat0$STATUSDATE, dat0$DATE.DIAG, unit = "days") 
time.na <- is.na(dat0$DOB) 
dat0$time1[time.na] <- dat0$time2[time.na] <- NA 

> dat0 
    ID STATUS STATUSDATE DATE.DIAG  DOB NUM.AFTER.DIAG time1  time2 
1 187  D 2000-07-15 1982-07-15  <NA>    0 NA NA days 
3 265  B 2011-03-01 1982-07-15  <NA>    0 NA NA days 
4 278  B 2011-03-01 1982-04-15  <NA>    0 NA NA days 
5 281  B 2011-03-01 1982-10-15 1967-01-15    0  0 10364 days 
7 283  D 1983-09-15 1982-05-15 1970-03-15    0  0 488 days 
10 291  B 2011-03-01 1981-07-15  <NA>    0 NA NA days 
11 292  B 2011-03-01 1982-01-15 1974-06-15    0  0 10637 days 
13 297  D 1987-06-15 1982-01-15 1968-04-15    0  0 1977 days 
14 299  D 1983-09-15 1982-04-15 1969-06-15    0  0 518 days 
15 305  D 1990-09-15 1981-07-15 1977-09-15    0  0 3349 days 
17 311  B 2011-03-01 1982-12-15 1975-04-15    0  0 10303 days 
26 333  D 1982-10-15 1981-09-15 1967-07-15    0  0 395 days 
29 334  D 1984-04-15 1982-03-15 1968-07-15    0  0 762 days 

2)是有點麻煩,但你實際上需要做的就是插入一個多行和計算時間變量:

## create subset with relevant observations 
dat.unfold <- dat[dat$NUM.AFTER.DIAG != 0, ] 
## compute time differences 
time1 <- difftime(dat.unfold$DOB, dat.unfold$DATE.DIAG, unit = "days") 
time1[time1 < 0] <- 0 
time2 <- difftime(dat.unfold$STATUSDATE, dat.unfold$DATE.DIAG, unit = "days") 

## calculate indices for individuals 
n.obs <- daply(dat.unfold, .(ID), function(z) max(z$NUM.AFTER.DIAG) + 1) 
df.new <- data.frame(ID = rep(unique(dat.unfold$ID), times = n.obs)) 
rle.new <- rle(df.new$ID) 
ind.last <- cumsum(rle.new$lengths) 
ind.first <- !duplicated(df.new$ID) 
ind.first.w <- which(ind.first) 
ind.second <- ind.first.w + 1 
ind2.to.last <- unlist(sapply(seq_along(ind.second), 
       function(z) ind.second[z]:ind.last[z])) 

## insert time variables 
df.new$time2 <- df.new$time1 <- NA 
df.new$time1[ind.first] <- 0 
df.new$time1[!ind.first] <- time1 
df.new$time2[!ind.first] <- time2 
df.new$time2[ind2.to.last - 1] <- time1 

這給了我:

> df.new 
    ID time1 time2 
1 258  0 8401 
2 258 8401 10425 
3 284  0 9039 
4 284 9039 10394 
5 319  0 2039 
6 319 2039 8827 
7 319 8827 9466 
8 319 9466 10333 
9 322  0 1065 
10 322 1065 2160 
11 322 2160 3346 
12 329  0 3287 
13 329 3287 4657 
14 329 4657 10456 

這應該爲STATUS工作變量和其他變量以類似的方式。 當兩個步驟都單獨工作時,您只需在末尾執行一個步驟rbind