88

I want to create a new column in a data.table calculated from the current value of one column and the previous of another. Is it possible to access previous rows?

E.g.:

> DT <- data.table(A=1:5, B=1:5*10, C=1:5*100)
> DT
   A  B   C
1: 1 10 100
2: 2 20 200
3: 3 30 300
4: 4 40 400
5: 5 50 500
> DT[, D := C + BPreviousRow] # What is the correct code here?

The correct answer should be

> DT
   A  B   C   D
1: 1 10 100  NA
2: 2 20 200 210
3: 3 30 300 320
4: 4 40 400 430
5: 5 50 500 540
4

8 回答 8

113

v1.9.6shift()中实现,这非常简单。

DT[ , D := C + shift(B, 1L, type="lag")]
# or equivalently, in this case,
DT[ , D := C + shift(B)]

来自新闻

  1. 新函数shift()实现lead/lagvectorlistdata.framesdata.tables的快速。它需要一个type参数,可以是"lag" (默认) 或"lead":=它可以与or一起使用非常方便set()。例如:DT[, (cols) := shift(.SD, 1L), by=id]。请查看?shift更多信息。

有关以前的答案,请参阅历史记录。

于 2013-02-04T15:02:24.710 回答
52

使用dplyr你可以做:

mutate(DT, D = lag(B) + C)

这使:

#   A  B   C   D
#1: 1 10 100  NA
#2: 2 20 200 210
#3: 3 30 300 320
#4: 4 40 400 430
#5: 5 50 500 540
于 2015-04-27T01:52:21.077 回答
24

几个人已经回答了具体问题。请参阅下面的代码,了解我在这种情况下使用的通用功能,它可能会有所帮助。您可以根据需要在“过去”或“未来”中查看尽可能多的行,而不仅仅是获取前一行。

rowShift <- function(x, shiftLen = 1L) {
  r <- (1L + shiftLen):(length(x) + shiftLen)
  r[r<1] <- NA
  return(x[r])
}

# Create column D by adding column C and the value from the previous row of column B:
DT[, D := C + rowShift(B,-1)]

# Get the Old Faithul eruption length from two events ago, and three events in the future:
as.data.table(faithful)[1:5,list(eruptLengthCurrent=eruptions,
                                 eruptLengthTwoPrior=rowShift(eruptions,-2), 
                                 eruptLengthThreeFuture=rowShift(eruptions,3))]
##   eruptLengthCurrent eruptLengthTwoPrior eruptLengthThreeFuture
##1:              3.600                  NA                  2.283
##2:              1.800                  NA                  4.533
##3:              3.333               3.600                     NA
##4:              2.283               1.800                     NA
##5:              4.533               3.333                     NA
于 2014-08-01T16:24:39.313 回答
12

根据上面@Steve Lianoglou 的评论,为什么不只是:

DT[, D:= C + c(NA, B[.I - 1]) ]
#    A  B   C   D
# 1: 1 10 100  NA
# 2: 2 20 200 210
# 3: 3 30 300 320
# 4: 4 40 400 430
# 5: 5 50 500 540

并避免使用seq_lenorhead或任何其他功能。

于 2014-05-04T04:25:05.617 回答
9

遵循 Arun 的解决方案,无需参考即可获得类似的结果.N

> DT[, D := C + c(NA, head(B, -1))][]
   A  B   C   D
1: 1 10 100  NA
2: 2 20 200 210
3: 3 30 300 320
4: 4 40 400 430
5: 5 50 500 540
于 2013-02-04T15:53:25.323 回答
1

我添加了一个填充参数并更改了一些名称并将其命名为shifthttps://github.com/geneorama/geneorama/blob/master/R/shift.R

于 2014-11-03T22:03:58.380 回答
1

这是我的直观解决方案:

#create data frame
df <- data.frame(A=1:5, B=seq(10,50,10), C=seq(100,500, 100))`
#subtract the shift from num rows
shift  <- 1 #in this case the shift is 1
invshift <- nrow(df) - shift
#Now create the new column
df$D <- c(NA, head(df$B, invshift)+tail(df$C, invshift))`

在这里invshift,行数减 1 为 4。nrow(df)为您提供数据框或向量中的行数。同样,如果您想取更早的值,请从 nrow 2、3、...等中减去,并将 NA 相应地放在开头。

于 2018-07-05T10:51:14.643 回答
-2

它可以在一个循环中完成。

# Create the column D
DT$D <- 0
# for every row in DT
for (i in 1:length(DT$A)) {
  if(i==1) {
    #using NA at first line
    DT[i,4] <- NA
  } else {
    #D = C + BPreviousRow
    DT[i,4] <- DT[i,3] + DT[(i-1), 2]   
  }
}

使用 for,您甚至可以使用此新列的行的先前值 DT[(i-1), 4]

于 2020-01-29T19:52:33.890 回答