将滞后操作向量化。

3

如何在 R 中向量化以下涉及使用 Z 的滞后值递归修改列 Z 的操作?

library(dplyr)
set.seed(5)

initial_Z=1000

df <- data.frame(X=round(100*runif(10),0), Y=round(100*runif(10),0))
df
    X  Y
1  20 27
2  69 49
3  92 32
4  28 56
5  10 26
6  70 20
7  53 39
8  81 89
9  96 55
10 11 84

df <- df %>%  mutate(Z=if_else(row_number()==1, initial_Z-Y, NA_real_)) 
df
    X  Y   Z
1  20 27 973
2  69 49  NA
3  92 32  NA
4  28 56  NA
5  10 26  NA
6  70 20  NA
7  53 39  NA
8  81 89  NA
9  96 55  NA
10 11 84  NA

for (i in 2:nrow(df)) {
  
  df$Z[i] <- (df$Z[i-1]*df$X[i-1]/df$X[i])-df$Y[i]
  
}
df
    X  Y           Z
1  20 27  973.000000
2  69 49  233.028986
3  92 32  142.771739
4  28 56  413.107143
5  10 26 1130.700000
6  70 20  141.528571
7  53 39  147.924528
8  81 89    7.790123
9  96 55  -48.427083
10 11 84 -506.636364

因此,Z的第一个值是根据初始值(initial_Z)和Y的第一个值设置的。其余的Z值通过使用X和Z滞后值以及当前的Y值进行计算。

我的实际数据框很大,并且需要在模拟中重复执行此操作数千次。使用for循环太耗时间了。我更喜欢使用dplyr来实现这个操作,但其他方法也可以。

提前感谢任何帮助。

2个回答

0

使用accumulate2也可以实现相同的功能。请注意,这些只是for循环。如果在R中出现问题,您应该考虑使用Rcpp编写for循环。

df %>%
  mutate(Z = accumulate2(Y, c(1, head(X, -1)/X[-1]), ~ ..1 * ..3 -..2, .init = 1000)[-1])

    X  Y         Z
1  20 27       973
2  69 49   233.029
3  92 32  142.7717
4  28 56  413.1071
5  10 26    1130.7
6  70 20  141.5286
7  53 39  147.9245
8  81 89  7.790123
9  96 55 -48.42708
10 11 84 -506.6364

您可以使用 unlist(Z)

df %>%
   mutate(Z = unlist(accumulate2(Y, c(1, head(X, -1)/X[-1]), ~ ..1 * ..3 -..2, .init = 1000))[-1])

0

我不知道你是否能避免 for 循环的影响,但一般情况下 R 应该对它们非常擅长。鉴于此,这是一个可能适合你的 Reduce 变量:

set.seed(5)
initial_Z=1000
df <- data.frame(X=round(100*runif(10),0), Y=round(100*runif(10),0))

df$Z <- with(df, Reduce(function(prevZ, i) {
  if (i == 1) return(prevZ - Y[i])
  prevZ*X[i-1]/X[i] - Y[i]
}, seq_len(nrow(df)), init = initial_Z, accumulate = TRUE))[-1]
df
#     X  Y           Z
# 1  20 27  973.000000
# 2  69 49  233.028986
# 3  92 32  142.771739
# 4  28 56  413.107143
# 5  10 26 1130.700000
# 6  70 20  141.528571
# 7  53 39  147.924528
# 8  81 89    7.790123
# 9  96 55  -48.427083
# 10 11 84 -506.636364

要明确一点,Reduce 内部使用 for 循环来遍历数据。我通常不喜欢将 索引 作为 Reducex 值,但由于 Reduce 只迭代一个值,而我们需要同时获取 XY,所以索引(行)是必需的步骤。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接