【发布时间】:2017-03-17 16:30:39
【问题描述】:
顺序累积计算
我需要进行时间序列计算,其中每一行计算的值取决于上一行计算的结果。我希望使用data.table 的便利。实际问题是一个水文模型——累积水平衡计算,在每个时间步增加降雨量并减去作为当前水量函数的径流和蒸发量。数据集包括不同的盆地和情景(组)。这里我将使用一个更简单的问题来说明。
计算的简化示例如下所示,对于每个时间步(行)i:
v[i] <- a[i] + b[i] * v[i-1]
a 和b 是参数值的向量,v 是结果向量。对于第一行(i == 1),v 的初始值为v0 = 0。
第一次尝试
我的第一个想法是在data.table 中使用shift()。一个最小的例子,包括想要的结果v.ans,是
library(data.table) # version 1.9.7
DT <- data.table(a = 1:4,
b = 0.1,
v.ans = c(1, 2.1, 3.21, 4.321) )
DT
# a b v.ans
# 1: 1 0.1 1.000
# 2: 2 0.1 2.100
# 3: 3 0.1 3.210
# 4: 4 0.1 4.321
DT[, v := NA] # initialize v
DT[, v := a + b * ifelse(is.na(shift(v)), 0, shift(v))][]
# a b v.ans v
# 1: 1 0.1 1.000 1
# 2: 2 0.1 2.100 2
# 3: 3 0.1 3.210 3
# 4: 4 0.1 4.321 4
这不起作用,因为 shift(v) 提供了原始列 v 的副本,移动了 1 行。它不受分配给v 的影响。
我也考虑过使用 cumsum() 和 cumprod() 来构建方程,但这也行不通。
蛮力方法
所以为了方便起见,我在函数内部使用了一个 for 循环:
vcalc <- function(a, b, v0 = 0) {
v <- rep(NA, length(a)) # initialize v
for (i in 1:length(a)) {
v[i] <- a[i] + b[i] * ifelse(i==1, v0, v[i-1])
}
return(v)
}
这个累积函数适用于 data.table:
DT[, v := vcalc(a, b, 0)][]
# a b v.ans v
# 1: 1 0.1 1.000 1.000
# 2: 2 0.1 2.100 2.100
# 3: 3 0.1 3.210 3.210
# 4: 4 0.1 4.321 4.321
identical(DT$v, DT$v.ans)
# [1] TRUE
我的问题
我的问题是,我能否以更简洁有效的data.table 方式编写此计算,而不必使用 for 循环和/或函数定义?也许使用set()?
或者有更好的方法吗?
编辑:更好的循环
David 的 Rcpp 解决方案启发了我从 for 循环中删除 ifelse():
vcalc2 <- function(a, b, v0 = 0) {
v <- rep(NA, length(a))
for (i in 1:length(a)) {
v0 <- v[i] <- a[i] + b[i] * v0
}
return(v)
}
vcalc2() 比 vcalc() 快 60%。
【问题讨论】:
-
可能最好根据 v0、a、b 来寻找封闭形式的解决方案。
-
“差分方程”是正确的术语吗?无论如何,如果是这样,除非找到封闭形式的解决方案,否则您无法按原样对计算进行矢量化。
-
感谢您的 cmets。通过封闭形式,我假设您的意思是随着时间的推移积分的代数表达式。这对于周期函数来说可能是可以想象的,比如正弦和余弦来表示季节性周期,但不是一般情况下,其中 a 和 b 是高度可变的环境变量(如降水、太阳辐射等)的函数。我认为你是对的向量化不可能。 @Frank,我不知道“差分方程”这个词是否适用。
-
我的意思是递归地替换术语,直到你有一个 a、b 和 v0 的函数。变量的性质无关紧要(不过,是的,完全循环的
a可能会简化它)。您有一个带有一些更新公式的初始条件,因此可以根据初始条件和其他数据来表达该值,而不是递归地进行。 -
我习惯于看到这类问题在执行此操作后会简化很多,例如stackoverflow.com/q/38577232,但您的问题可能并非如此。在这里,我想我只是解决了矩阵代数和大量冗余计算,比如
m = matrix(1, .N+1L, .N); n = col(m) - row(m) + 1L; m[] = b^n*(n >= 0L); c(c(v0, a) %*% m),但我仍然认为对于这类问题来说这是一个值得的标准练习......
标签: r data.table time-series vectorization difference-equations