当所需的插值点与可用数据相比稀疏时,进行线性插值的最有效方法是什么?我有一个非常长的数据框,包含许多列,其中一列代表一个时间戳,其余的是变量,我有兴趣在极少数时间戳内插。例如,考虑两个变量大小写:
microbenchmark::microbenchmark(approx(1:2, 1:2, 1.5)$y)
# Unit: microseconds
# expr min lq mean median uq max neval
# ... 39.629 41.3395 46.80514 42.195 52.8865 138.558 100
microbenchmark::microbenchmark(approx(seq_len(1e6), seq_len(1e6), 1.5)$y)
# Unit: milliseconds
# expr min lq mean median uq max neval
# ... 129.5733 231.0047 229.3459 236.3845 247.3096 369.4621 100
我们看到虽然只需要一个插值(t = 1.5
),但增加对(x, y)
的数量可能会导致运行时间差异达到几个数量级。
另一个例子,这次是数据表。
library(data.table)
tmp_dt <- data.table(time = seq_len(1e7), a = seq_len(1e7), b = seq_len(1e7), c = seq_len(1e7))
运行tmp_dt[, lapply(.SD, function(col) {approx(time, col, 1.5)$y}), .SDcols = c("a", "b", "c")]
会生成一行数据表,但需要一段时间。
我认为通过删除数据表中不需要插值的所有行,必须有一些效率。
答案 0 :(得分:2)
如果你的线性插值是weighted.mean(c(x0, x1), c(t1-t, t-t0))
,其中(t0, x0)
是下面最近的点,(t1, x1)
是最近的......
# fix bad format
tmp_dt[, names(tmp_dt) := lapply(.SD, as.numeric)]
# enumerate target times
tDT = data.table(t = seq(1.5, 100.5, by=.5))
# handle perfect matches
tDT[, a := tmp_dt[.SD, on=.(time = t), x.a]]
# handle interpolation
tDT[is.na(a), a := {
w = findInterval(t, tmp_dt$time)
cbind(tmp_dt[w, .(t0 = time, a0 = a)], tmp_dt[w+1L, .(t1 = time, a1 = a)])[,
(a0*(t1-t) + a1*(t-t0))/(t1-t0)]
}]
对更多列的扩展有点混乱,但可以在这里进行加工。
某种滚动,如w = tmp_dt[t, on=.(time), roll=TRUE, which=TRUE]
,可能比findInterval
更快,但我还没有调查过。