我尝试向data.table
添加新列,其中行中的值取决于行中值的相对关系。更确切地说,如果一行中有一个值X,我想知道在X-30中有多少其他值在同一列(和组)中。
就是这样:
DT<-data.table(
X = c(1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1),
Y = c(100, 101, 133, 134, 150, 156, 190, 200, 201, 230, 233, 234),
Z = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
我想获得一个新列,其值为:
N <- c(0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 2)
我已经尝试了以下方法,但我没有得到我可以使用的结果:
DT[,list(Y,num=cumsum(Y[-.I]>DT[.I,Y]-30),Z),by=.(X)]
任何想法如何做到这一点?
答案 0 :(得分:6)
这可能是通过滚动连接(?)实现的,但现在是foverlaps
替代
DT[, `:=`(indx = .I, Y2 = Y - 30L, N = 0L)] # Add row index and a -30 interval
setkey(DT, X, Y2, Y) # Sort by X and the intervals (for fovelaps)
res <- foverlaps(DT, DT)[Y2 > i.Y2, .N, keyby = indx] # Run foverlaps and check what can we catch
setorder(DT, indx) # go back to the original order
DT[res$indx, N := res$N][, c("indx", "Y2") := NULL] # update results and remove cols
DT
# X Y Z N
# 1: 1 100 1 0
# 2: 2 101 2 0
# 3: 2 133 3 0
# 4: 1 134 4 0
# 5: 1 150 5 1
# 6: 2 156 6 1
# 7: 1 190 7 0
# 8: 2 200 8 0
# 9: 2 201 9 1
# 10: 1 230 10 0
# 11: 1 233 11 1
# 12: 1 234 12 2
或者,使用which=TRUE
的{{1}}选项使重叠合并更小:
foverlaps
答案 1 :(得分:4)
这是另一种方式:
DT[order(Y), N := 0:(.N-1) - findInterval(Y - 30, Y), by = X]
all.equal(DT$N,N) # TRUE