2016-02-03 29 views
2

不知道是否有更智能,更快捷的方法来做到这一点。按因子水平索引重复数据帧的行

说我有这个数据帧:

library(dplyr) 
set.seed(1) 
ddf <- data.frame(time=1:20, id=rep(letters[1:5], each=20)) 
ddf <- ddf %>% group_by(id) %>% mutate(val1 = rnorm(20), val2 = cumsum(val1)) 

我想要做的就是创建这个数据帧的20份。 (20,因为有20个独特的时间值)。但是,对于每个副本,我不想包含当前的最后时间值。所以第一个副本应该复制ddf的所有行。第二个副本应该复制除ddf $ time == 20之外的所有ddf行。下一个副本应该复制除ddf $ time == 20或ddf $ time == 19之外的所有行,依此类推等等,直到最终副本只复制ddf $ time == 1

这里是我的解决方案:

ddfx <- NULL 
for(i in 1:length(unique(ddf$time))){ 
    ddfx[[i]] <- ddf %>% filter(time<= i) 
} 

ddfz <- do.call('rbind', Map(cbind, ddfx, ival = 1:length(unique(ddf$time)))) 

它可以做得更快,更简单吗?

+1

或'地图(函数(X,Y)×X (data.table); $ time <= y,],list(ddf),20:1)'data.table'爱好者的' – thelatemail

+0

。 setDT(ddf)[order(-time),copies:= rleid(time)]; ddf < - ddf [rep(1:.N,copies)] [,copies:= NULL]' – tospig

+0

需要确定这些实际上是日期时间值。由于不理解R类,找到字符值(或因子类)并不令人惊讶。 (如果它正常工作,这看起来像一个相当简单的解决方案。) –

回答

1

谈到我的意见变成一个答案,如果你使用data.table你可以做

setDT(ddf)[order(-time) , copies := rleid(time) ] 
ddf <- ddf[rep(1:.N, copies)][, copies:=NULL] 
ddf 

# time id  val1  val2 
# 1: 1 a -0.6264538 -0.6264538 
# 2: 1 a -0.6264538 -0.6264538 
# 3: 1 a -0.6264538 -0.6264538 
# 4: 1 a -0.6264538 -0.6264538 
# 5: 1 a -0.6264538 -0.6264538 
# ---        
# 1046: 18 e -0.5732654 4.0950292 
# 1047: 18 e -0.5732654 4.0950292 
# 1048: 19 e -1.2246126 2.8704166 
# 1049: 19 e -1.2246126 2.8704166 
# 1050: 20 e -0.4734006 2.3970160 

## quick check 
table(ddf$time) 
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
# 100 95 90 85 80 75 70 65 60 55 50 45 40 35 30 25 20 15 10 5 

说明

运行长度编码(RLE)?rle(或?data.table::rleid

计算向量中等值运行的长度和值

这意味着它将相同的值按顺序排列。由于所需的“复制”取决于time,因此我们可以在order时间内将数据中相同的值放在一起。

rle然后从1

编码相等的值成顺序组,则我们可以使用那些组识别为副本,我们要求各组的数目。

速度比较

正如你更快的速度后,这里是一个比较原始的和Map解决方案

fun_orig <- function(x){ 
    ddfz <- do.call('rbind', Map(cbind, ddfx, ival = 1:length(unique(ddf$time)))) 
    return(ddfz) 
} 

fun_map <- function(x){ 
    df <- Map(function(x,y) x[x$time <= y,], list(ddf), 20:1) 
    return(df) 
} 

fun_dt <- function(x){ 
    setDT(ddf)[order(-time) , copies := rleid(time) ] 
    ddf <- ddf[rep(1:.N, copies)][, copies:=NULL][] 
    return(ddf) 
} 


library(microbenchmark) 

microbenchmark(fun_orig(ddf), fun_map(ddf), fun_dt(ddf)) 
# Unit: microseconds 
#   expr  min  lq  mean median  uq  max neval cld 
# fun_orig(ddf) 4396.559 4547.975 4883.709 4646.162 4784.530 8002.254 100 c 
# fun_map(ddf) 3341.207 3497.490 3651.714 3588.343 3649.953 6799.140 100 b 
# fun_dt(ddf) 862.612 955.883 1030.185 998.363 1038.336 3850.275 100 a