基于条件的动态偏移
Dynamic offset based on condition
我的 data.table
如下所示。
library(data.table)
my_dt <- data.table(time = c(1000, 1111, 2000, 3000, 4500, 4600, 5000, 7000, 8500, 9000),
var1 = 1:10,
var2 = c(0.5, 0.6, 2, 0.8, 2.1, 1, 7, 8, 0.1, 0.3))
#printed table:
time var1 var2
1: 1000 1 0.5
2: 1111 2 0.6
3: 2000 3 2.0
4: 3000 4 0.8
5: 4500 5 2.1
6: 4600 6 1.0
7: 5000 7 7.0
8: 7000 8 8.0
9: 8500 9 0.1
10: 9000 10 0.3
对于 var1 中的每个值,我需要找到 var2 中第一个值的行索引等于 to/greater 然后是 var1 中的值。然后我需要通过减去 time col 中的相应值来计算 time 的差异。
例如:var1 中的第一个值是 1(也是行索引 1)。 var2 中等于 to/greater 然后 1 的第一个值是 2.0 并且在行索引 3 处。因此相应的时间差是 2000 - 1000 = 1000:
my_dt$time[3] - my_dt$time[1]
所需的结果如下所示。我实际上不需要 idx 列,但它可能有助于作为中间结果。
my_result <- data.table(time = c(1000, 1111, 2000, 3000, 4500, 4600, 5000, 7000, 8500, 9000),
var1 = 1:10,
var2 = c(0.5, 0.6, 2, 0.8, 2.1, 1, 7, 8, 0.1, 0.3),
idx = c(3, 3, 7, 7, 7, 7, 7, 8, 0, 0),
time.diff = c(1000, 889, 3000, 2000, 500, 400, 0, 0, NA, NA))
#printed result:
time var1 var2 idx time.diff
1: 1000 1 0.5 3 1000
2: 1111 2 0.6 3 889
3: 2000 3 2.0 7 3000
4: 3000 4 0.8 7 2000
5: 4500 5 2.1 7 500
6: 4600 6 1.0 7 400
7: 5000 7 7.0 7 0
8: 7000 8 8.0 8 0
9: 8500 9 0.1 0 NA
10: 9000 10 0.3 0 NA
我可以通过结合使用 for 和 while 循环来实现这个结果。然而,执行速度非常缓慢。我想知道是否有更好的解决方案 a) 使用 data.table
语法创建 col idx 和 b) 使用 idx 中的值作为shift()
中的偏移参数 (n)?非常感谢!
my_dt[,idx := max.col(outer(var1, var2, '<='), 'first')][,
idx := idx * NA^(var2[idx]<var1)][,
time_diff := time[idx] - time][]
time var1 var2 idx time_diff
1: 1000 1 0.5 3 1000
2: 1111 2 0.6 3 889
3: 2000 3 2.0 7 3000
4: 3000 4 0.8 7 2000
5: 4500 5 2.1 7 500
6: 4600 6 1.0 7 400
7: 5000 7 7.0 7 0
8: 7000 8 8.0 8 0
9: 8500 9 0.1 NA NA
10: 9000 10 0.3 NA NA
正在将我的评论转换为答案以便回答问题
my_dt[, time.diff := .SD[my_dt, time - i.time, on = .(var2 >= var1), mult = "first"]]
基本上,
my_dt[my_dt, on = .(var2 >= var1)]
是自non-equi加入。
mult = "first"
仅用于选择第一个匹配项,否则它将把每个 var1
连接到所有 <= var2
值
因为它是一个self-join,两个table有相同的列,因此i.
前缀代表table中的列第 i
位(如 DT[i, j, by]
)
关于 .SD
部分,只是因为赋值运算符 (:=
) 打乱了顺序,意思是,以下行有效(没有赋值),但是搞砸它。可能与data.table[i, j, by]
内部的操作顺序有关
my_dt[my_dt, time - i.time, on = .(var2 >= var1), mult = "first"]
# [1] 1000 889 3000 2000 500 400 0 0 NA NA
我的 data.table
如下所示。
library(data.table)
my_dt <- data.table(time = c(1000, 1111, 2000, 3000, 4500, 4600, 5000, 7000, 8500, 9000),
var1 = 1:10,
var2 = c(0.5, 0.6, 2, 0.8, 2.1, 1, 7, 8, 0.1, 0.3))
#printed table:
time var1 var2
1: 1000 1 0.5
2: 1111 2 0.6
3: 2000 3 2.0
4: 3000 4 0.8
5: 4500 5 2.1
6: 4600 6 1.0
7: 5000 7 7.0
8: 7000 8 8.0
9: 8500 9 0.1
10: 9000 10 0.3
对于 var1 中的每个值,我需要找到 var2 中第一个值的行索引等于 to/greater 然后是 var1 中的值。然后我需要通过减去 time col 中的相应值来计算 time 的差异。 例如:var1 中的第一个值是 1(也是行索引 1)。 var2 中等于 to/greater 然后 1 的第一个值是 2.0 并且在行索引 3 处。因此相应的时间差是 2000 - 1000 = 1000:
my_dt$time[3] - my_dt$time[1]
所需的结果如下所示。我实际上不需要 idx 列,但它可能有助于作为中间结果。
my_result <- data.table(time = c(1000, 1111, 2000, 3000, 4500, 4600, 5000, 7000, 8500, 9000),
var1 = 1:10,
var2 = c(0.5, 0.6, 2, 0.8, 2.1, 1, 7, 8, 0.1, 0.3),
idx = c(3, 3, 7, 7, 7, 7, 7, 8, 0, 0),
time.diff = c(1000, 889, 3000, 2000, 500, 400, 0, 0, NA, NA))
#printed result:
time var1 var2 idx time.diff
1: 1000 1 0.5 3 1000
2: 1111 2 0.6 3 889
3: 2000 3 2.0 7 3000
4: 3000 4 0.8 7 2000
5: 4500 5 2.1 7 500
6: 4600 6 1.0 7 400
7: 5000 7 7.0 7 0
8: 7000 8 8.0 8 0
9: 8500 9 0.1 0 NA
10: 9000 10 0.3 0 NA
我可以通过结合使用 for 和 while 循环来实现这个结果。然而,执行速度非常缓慢。我想知道是否有更好的解决方案 a) 使用 data.table
语法创建 col idx 和 b) 使用 idx 中的值作为shift()
中的偏移参数 (n)?非常感谢!
my_dt[,idx := max.col(outer(var1, var2, '<='), 'first')][,
idx := idx * NA^(var2[idx]<var1)][,
time_diff := time[idx] - time][]
time var1 var2 idx time_diff
1: 1000 1 0.5 3 1000
2: 1111 2 0.6 3 889
3: 2000 3 2.0 7 3000
4: 3000 4 0.8 7 2000
5: 4500 5 2.1 7 500
6: 4600 6 1.0 7 400
7: 5000 7 7.0 7 0
8: 7000 8 8.0 8 0
9: 8500 9 0.1 NA NA
10: 9000 10 0.3 NA NA
正在将我的评论转换为答案以便回答问题
my_dt[, time.diff := .SD[my_dt, time - i.time, on = .(var2 >= var1), mult = "first"]]
基本上,
my_dt[my_dt, on = .(var2 >= var1)]
是自non-equi加入。mult = "first"
仅用于选择第一个匹配项,否则它将把每个var1
连接到所有<= var2
值因为它是一个self-join,两个table有相同的列,因此
i.
前缀代表table中的列第i
位(如DT[i, j, by]
)关于
内部的操作顺序有关.SD
部分,只是因为赋值运算符 (:=
) 打乱了顺序,意思是,以下行有效(没有赋值),但是搞砸它。可能与data.table[i, j, by]
my_dt[my_dt, time - i.time, on = .(var2 >= var1), mult = "first"] # [1] 1000 889 3000 2000 500 400 0 0 NA NA