2016-02-03 50 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