簡體   English   中英

如何根據列值創建附加行或 dataframe

[英]How to create additional rows or a dataframe based on column values

以下是一些示例數據:

df <- data.frame(ID = c(1, 2, 2), 
                 Amount = c(100, 10, 100),
                 Time = c(0, 0, 24),
                 ADDL = c(5, 0, 1),
                 II = c(24, 24, 24))

使用此 dataframe 我想生成以下行/數據幀,其中 ADDL 是應為給定 ID 生成的附加行數,II 項是每個新行應采用的時間間隔。

#      ID Amount Time 
# 1    1  100    0
# 2    1  100    24
# 3    1  100    48
# 4    1  100    72
# 5    1  100    96
# 6    1  100    120
# 7    2  10     0
# 8    2  100    24
# 9    2  100    48

我將生成的 output dataframe 將具有 >350000 行,因此需要一個有效的解決方案。

解決方案3:使用bind_rows ,如下所示。 這比其他兩種解決方案更快。

####  solution 3
  df3 <- setDT(df)
  mydf3 <- setDT(df)
  m1 <- proc.time()
  datalist = list()
  
  for (i in 1:n) {
    dlist = list()
    if ( df3$ADDL[i]>0){
      for(j in 1:df3$ADDL[i]){
        dat <- data.table(ID=df3$ID[i],
                          Amount=df3$Amount[i],
                          Time=df3$Time[i]+j*df3$II[i],
                          ADDL=df3$ADDL[i],
                          II=df3$II[i])
        dlist[[j]] <- dat # add it to your list
      }
      datalist[[i]] <- dlist
    }
    
  }
  datalist[[n+1]] <- mydf3
  all_data <- dplyr::bind_rows(datalist)
  all_data[order(ID,Time)]
  m2 <- proc.time()
  print((m2 - m1)[[3]])

>   all_data[order(ID,Time)]
   ID Amount Time ADDL II
1:  1    100    0    5 24
2:  1    100   24    5 24
3:  1    100   48    5 24
4:  1    100   72    5 24
5:  1    100   96    5 24
6:  1    100  120    5 24
7:  2     10    0    0 24
8:  2    100   24    1 24
9:  2    100   48    1 24

舊答案:您可以使用lapply來完成此操作。 以下代碼在您的df上給出了預期的結果。 您可以從mydf dataframe 中刪除不需要的變量。 更新:我有兩個解決方案。 對於大量數據,第二種解決方案更好,因為它使用 rbindlist 和 data.table - 兩者都在 C 中實現,因此效率更高。

##  Solution 1 in R should suffice for small data frames

mydf <- df
  lapply(1:n, function(i){
    if (df$ADDL[i]>0){
      lapply(1:df$ADDL[i], function(j){
        mydf<<- rbind(mydf,data.frame(ID=df$ID[i],
                                      Amount=df$Amount[i],
                                      Time=df$Time[i]+j*df$II[i],
                                      ADDL=df$ADDL[i],
                                      II=df$II[i]))
      })
    }
  })
  
  mydf[order(mydf$ID,mydf$Time),]
  
  ##  Solution 2 is more efficient for large data - uses data.table and rbindlist
  
  mydf2 <- setDT(df)
  lapply(1:n, function(i){
    if (df$ADDL[i]>0){
      lapply(1:df$ADDL[i], function(j){
        addrow <- data.table(ID=df$ID[i],
                             Amount=df$Amount[i],
                             Time=df$Time[i]+j*df$II[i],
                             ADDL=df$ADDL[i],
                             II=df$II[i])
        mydf2<<- rbindlist(list(mydf2,addrow), use.names=TRUE)
      })
    }
  })
  
  mydf2[order(ID,Time)]
  
  identical(mydf2, setDT(mydf)) 

> identical(mydf2, setDT(mydf))
[1] TRUE  
#fastest option stays away from adding rows using a loop

#add rows function
addRows <- function(x){
  Times <- seq(from = x$Time, to = x$Time + x$ADDL*x$II, by = x$II)
  n <- length(Times)
  x %>% 
    dplyr::slice(rep(row_number(),n)) %>%
    dplyr::mutate(Time = Times)
}

df %>%
  dplyr::group_by(USUBJID, TIME, ADDL) %>%
  dplyr::group_split() %>%
  purrr::map_dfr( ~ addRows(.))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM