r - 如何在数据帧计算中用矢量函数替换 R 中的 for 循环?

标签 r iteration vectorization rolling-computation accumulate

我一直在努力避免在 R 中使用 for 循环以加快计算和简化,尽可能地依赖向量函数。到目前为止,我已经成功了,直到遇到某些摊销计算。我碰壁了,不得不求助于 for 循环,请参阅下面的 MWE 代码。它工作正常,但我想用 vector 或其他更高效的函数替换它。有人可以帮我用向量函数替换下面的内容吗?

在从中提取此 MWE 的完整代码中,它使用 Shiny 进行响应。周期和向量速率,实际上是所有变量,都会根据用户输入发生剧烈变化。 MWE 示例输入变量已简化。

无论如何,以下是一种非常笨拙的电锯方法,需要精简。但是我不知道如何从我最有经验的完整 XLS 思维方式来处理这个问题。如果 for 循环是此类计算的唯一可行选择,我欢迎提出任何改进以下 MWE 的建议。

最底部是用于“矢量化”的有缺陷尝试的代码,但当矢量变量随时间变化时结果不准确。我在底部的图像中展示了这种矢量化方法的一个问题,当从一个时期移动到下一个时期时,期末/期初余额不匹配(for-loop MWE 代码没有这些问题 - 它是功能性的但 super 笨拙)。

For 循环 MWE 代码:

periods        <- 10
beginBal       <- 1000
yield_vector   <- c(0.30,0.30,0.30,0.30,0.30,0.28,0.26,0.20,0.18,0.20)
npr_vector     <- c(0.30,0.30,0.30,0.30,0.30,0.30,0.30,0.30,0.30,0.30)
mpr_vector     <- c(0.20,0.20,0.20,0.20,0.20,0.20,0.20,0.20,0.20,0.20)
default_vector <- c(0.10,0.10,0.10,0.10,0.10,0.09,0.08,0.07,0.06,0.05)

amort <- data.frame(period=seq(1,periods,1),
                    beginBal=rep(NA,periods),
                    yield=rep(NA,periods,),
                    purchases=rep(NA,periods),
                    payments=rep(NA,periods),
                    defaults=rep(NA,periods),
                    endBal=rep(NA,periods))

# Completes first row of data frame
amort[1,2] <- beginBal
amort[1,3] <- beginBal * yield_vector[1]/12
amort[1,4] <- beginBal * npr_vector[1]
amort[1,5] <- beginBal * mpr_vector[1]
amort[1,6] <- beginBal * default_vector[1] / 12
amort[1,7] <- beginBal + amort[1,4] - amort[1,5] - amort[1,6]

# Completes remaining rows of data frame
for(i in 2:nrow(amort)){
amort[i,2] <- amort[i-1,7]
amort[i,3] <- amort[i,2] * yield_vector[i]/12
amort[i,4] <- amort[i,2] * npr_vector[i]
amort[i,5] <- amort[i,2] * mpr_vector[i]
amort[i,6] <- amort[i,2] * default_vector[i]/12
amort[i,7] <- amort[i,2] + amort[i,4] - amort[i,5] - amort[i,6]
}
amort

这是一个看起来很漂亮但有缺陷的矢量化尝试,请参见下图中的输出缺陷之一(这些问题不会出现在上面的 for 循环 MWE 中):

amort           <- data.frame(period=seq(1,periods,1))
amort$beginBal  <- beginBal*(1-(mpr_vector[]+default_vector[]/12-npr_vector[]))^(amort$period-1)
amort$yield     <- amort$beginBal*yield_vector[]/12
amort$purchases <- amort$beginBal*npr_vector[]
amort$payments  <- amort$beginBal*mpr_vector[]
amort$defaults  <- amort$beginBal*default_vector[]/12
amort$endBal    <- amort$beginBal+amort$purchases-amort$payments-amort$defaults

amort <- cbind(amort,yield_vector,npr_vector,mpr_vector,default_vector)
amort

enter image description here

最佳答案

你可以这样做:

f <- function(x, y){
  x  * (1 + npr_vector[y] - mpr_vector[y] -  default_vector[y] / 12)
}

res <- Reduce(f, seq(periods), init = beginBal, accumulate = TRUE)
b <- head(res, -1)

result <- data.frame(period = seq(periods), beginBal = b,  yield = b * yield_vector/ 12,
           purchases = b * npr_vector,  payments = b * mpr_vector, 
           defaults = b * default_vector/12,   endBal = res[-1])

检查:

result
   period beginBal    yield purchases payments  defaults   endBal
1       1 1000.000 25.00000  300.0000 200.0000  8.333333 1091.667
2       2 1091.667 27.29167  327.5000 218.3333  9.097222 1191.736
3       3 1191.736 29.79340  357.5208 238.3472  9.931134 1300.979
4       4 1300.979 32.52446  390.2936 260.1957 10.841488 1420.235
5       5 1420.235 35.50587  426.0705 284.0470 11.835291 1550.423
6       6 1550.423 36.17654  465.1269 310.0846 11.628174 1693.837
7       7 1693.837 36.69981  508.1512 338.7675 11.292249 1851.929
8       8 1851.929 30.86548  555.5786 370.3858 10.802918 2026.319
9       9 2026.319 30.39478  607.8956 405.2637 10.131594 2218.819
10     10 2218.819 36.98032  665.6457 443.7638  9.245079 2431.456
 

all.equal(result, amort)
[1] TRUE

关于r - 如何在数据帧计算中用矢量函数替换 R 中的 for 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68398411/

相关文章:

r - 使用 ggplot2 的线图中误差线的宽度

r - 对存储为字符串的数字进行 R 数据表列的自定义排序

pandas - 移动 Pandas 列,然后取接下来 3 个值的平均值 (post_shift)

c - 实现范围数据类型

python - 通过组合来自三个不均匀长度列表的数字来创建一个数字列表

C++ 优化向量化嵌套循环

python - 如何向量化一系列标记

r - 何时在 R 中使用 for 循环

r - 获取第二个大写字母之前的子字符串

r - ggExtra绘图格式:不同绘图尺寸的相似边际绘图