[英]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.