通过在 R 中的数据帧的行上应用 Reduce 函数来创建一个新列
Create a new column by applying a Reduce function over rows of a dataframe in R
我有一个包含 ID、日期和观察值的数据框 returns。可以类比为:
df <- data.frame(
ID = gl(3, 10, labels = c("A", "B", "C")),
Date = factor(rep(2006, 2015, 3)),
lr = runif(30, -0.01, 0.01))
现在我想使用以下函数来查找每个 ID 的指数移动平均向量,并将它们作为新列添加到我的原始数据框中:
Emean<-function(x){
ema <- function(a,b) {lambda*a+(1-lambda)*b}
Reduce(ema, x, accumulate=T)
}
所以我希望生成的数据框包含 ID、Date、lr 和 mlr 列。最后一列 (mlr) 将使用上述函数计算;和(对不起,我的符号太松散了!)但这是公式:
mlr_t=lambda*mlr_t-1 + (1-lambda)*lr_t
'_t'表示时间。
现在正如我所说,我想将我的函数应用于按 ID 分组的行,并将结果作为列添加到此数据框中。 'Reduce' 的输出不能直接添加到该数据框,我必须分几步操作它,这在 R 中非常耗时。
我需要一个计算效率高的解决方案来完成我所说的。在实际数据集中,我有 +100K 个 ID,每个 ID 有 +250 个日期。
作为
mlr_0 = 0
mlr_1 = 0 + (1-lambda)*lr_1
mlr_2 = lambda * mlr_1 + (1-lambda)*lr_2
= lambda * (1-lambda) * lr_1 + (1-lambda)*lr_2
mlr_3 = lambda * mlr_2 + (1-lambda)*lr_3
= lambda^2 * (1-lambda) * lr_1 + lambda * (1-lambda) * lr_2 + (1-lambda)*lr_3
...
mlr_t = lambda^(t-1) * (1-lambda) * lr_1 + lambda^(t-2) * (1-lambda) * lr_2 + ...
= \Sum_{i=1}^{t} lambda^(t-i) * (1-lambda)*lr_i
你可以这样做(使用 data.table
)
setDT(df)
lambda <- 0.5
# This calculates the lambda^(t-i)
l <- function(i, lambda){ lambda^(i-seq_len(i)) }
# This calculates multiplies element wise and sums up the mlr_3
my_fun <- function(x, lr, lambda){
sum((1-lambda) * c(0,lr)[1:x] * l(x, lambda))}
# Apply both function to the vector
df[, vapply(seq_len(.N), my_fun, numeric(1), lr, lambda) ,by = ID]
结果(set.seed(42)
)
ID V1
1: A 0.0000000
2: A 0.4574030
3: A 0.6972392
4: A 0.4916894
5: A 0.6610685
6: A 0.6514070
7: A 0.5852515
8: A 0.6609199
9: A 0.3977932
10: A 0.5273928
11: B 0.0000000
12: B 0.2288709
...
我有一个包含 ID、日期和观察值的数据框 returns。可以类比为:
df <- data.frame(
ID = gl(3, 10, labels = c("A", "B", "C")),
Date = factor(rep(2006, 2015, 3)),
lr = runif(30, -0.01, 0.01))
现在我想使用以下函数来查找每个 ID 的指数移动平均向量,并将它们作为新列添加到我的原始数据框中:
Emean<-function(x){
ema <- function(a,b) {lambda*a+(1-lambda)*b}
Reduce(ema, x, accumulate=T)
}
所以我希望生成的数据框包含 ID、Date、lr 和 mlr 列。最后一列 (mlr) 将使用上述函数计算;和(对不起,我的符号太松散了!)但这是公式:
mlr_t=lambda*mlr_t-1 + (1-lambda)*lr_t
'_t'表示时间。
现在正如我所说,我想将我的函数应用于按 ID 分组的行,并将结果作为列添加到此数据框中。 'Reduce' 的输出不能直接添加到该数据框,我必须分几步操作它,这在 R 中非常耗时。
我需要一个计算效率高的解决方案来完成我所说的。在实际数据集中,我有 +100K 个 ID,每个 ID 有 +250 个日期。
作为
mlr_0 = 0
mlr_1 = 0 + (1-lambda)*lr_1
mlr_2 = lambda * mlr_1 + (1-lambda)*lr_2
= lambda * (1-lambda) * lr_1 + (1-lambda)*lr_2
mlr_3 = lambda * mlr_2 + (1-lambda)*lr_3
= lambda^2 * (1-lambda) * lr_1 + lambda * (1-lambda) * lr_2 + (1-lambda)*lr_3
...
mlr_t = lambda^(t-1) * (1-lambda) * lr_1 + lambda^(t-2) * (1-lambda) * lr_2 + ...
= \Sum_{i=1}^{t} lambda^(t-i) * (1-lambda)*lr_i
你可以这样做(使用 data.table
)
setDT(df)
lambda <- 0.5
# This calculates the lambda^(t-i)
l <- function(i, lambda){ lambda^(i-seq_len(i)) }
# This calculates multiplies element wise and sums up the mlr_3
my_fun <- function(x, lr, lambda){
sum((1-lambda) * c(0,lr)[1:x] * l(x, lambda))}
# Apply both function to the vector
df[, vapply(seq_len(.N), my_fun, numeric(1), lr, lambda) ,by = ID]
结果(set.seed(42)
)
ID V1
1: A 0.0000000
2: A 0.4574030
3: A 0.6972392
4: A 0.4916894
5: A 0.6610685
6: A 0.6514070
7: A 0.5852515
8: A 0.6609199
9: A 0.3977932
10: A 0.5273928
11: B 0.0000000
12: B 0.2288709
...