2017-04-17 64 views
3

我有一個包含兩列的data.table。當滿足條件時將data.table列值向前運行

dt = data.table(a = c(0,0,-1,rep(0,3),-1,1), b = c(1,2,3,2,4,2,4,5)) 
> dt 
    a b 
1: 0 1 
2: 0 2 
3: -1 3 
4: 0 2 
5: 0 4 
6: 0 2 
7: -1 4 
8: 1 5 

我需要發生的是隨時隨地列==我需要在B列結轉到現場的下一行,其中列== -1,前值-1。如果沒有更多的-1s然後在B列的值需要一直持續到data.table

這到底是我希望的

a b 
1: 0 1 
2: 0 2 
3: -1 3 
4: 0 3 
5: 0 3 
6: 0 3 
7: -1 4 
8: 1 4 

回答

3

好的結果,這不是和我原先想象的一樣困難。我可以刪除這個問題,如果有必要,但我還沒有在stackoverflow上找到任何類似的東西,所以我現在只是發佈我的解決方案。

第一種解決方案存在問題。這實際上是我所期望的,但我相信有一個更快的方法來計算這個。

library(data.table) 
dt = data.table(a = c(0,0,-1,rep(0,3),-1,1), b = c(1,2,3,2,4,2,4,5)) 

indices = which(dt$a == -1) 
values = dt$b[indices] 

dt[ , "tmp" := findInterval(1:nrow(dt), indices)] 

dt$b = mapply(function(tmp, b){ 
         if(tmp == 0){ 
         return(b) 
         }else{ 
         return(values[tmp]) 
         } 
        }, dt$tmp, dt$b) 

dt[ , "tmp" := NULL] 

> dt 
    a b 
1: 0 1 
2: 0 2 
3: -1 3 
4: 0 3 
5: 0 3 
6: 0 3 
7: -1 4 
8: 1 4 

更好溶液由於@Frank

dt[, tmp := cumsum(a==-1)][tmp > 0L, b := first(b), by=tmp][, tmp := NULL ] 
+4

據透露,更快和更標準:'DT [,B:=第一( b),通過= cumsum(a == - 1)]' – Frank

+0

@Frank謝謝,這是一個更好的解決方案 – Kristofersen

+0

@Frank實際上,這並不奏效。它會將第一個-1之前的值更改爲該組中的最小值。這些值應該保持不變。 – Kristofersen

2

也許像這樣在基R:

x <- c(which(dt==-1), nrow(dt)+1) 
#[1] 3 7 9 
dt[x[1]:nrow(dt),]$b <- rep(dt$b[head(x,-1)], diff(x)) 

# a b 
#1: 0 1 
#2: 0 2 
#3: -1 3 
#4: 0 3 
#5: 0 3 
#6: 0 3 
#7: -1 4 
#8: 1 4