r - 如何在这个简单的 R 代码中使用向量函数而不是 FOR 循环?
问题描述
这是我昨天发布的同名问题的扩展。昨天我过度简化了我的示例,因为还有其他变量可以驱动这个摊销示例。我想在下面的 R 代码中使用向量函数而不是 FOR 循环。下面的效果很好(我还在下面显示了正确的输出),但我理解随着模型的增长,向量函数会变得更快。
我有 Excel/VBA 背景,是 R 的新手,我正试图了解 R 向量。
摊销 = begin_bal*((1+npr)(1-mpr)(1-co/12)) = end_bal。下面的 Fin(收益率)不计入期末余额。
下面是 FOR 循环代码:
n_periods <- 8
begin_bal <- 10000
yld <- .20
npr <- .09
mpr <- .10
co <- .10
period <- seq(0, n_periods, 1)
fin <- 0
pur <- 0
pmt <- 0
ch_off <- 0
end_bal <- begin_bal
for (i in 1:n_periods) {
fin[i + 1] <- end_bal[i]*yld / 12
pur[i + 1] <- end_bal[i]*npr
pmt[i + 1] <- end_bal[i]*mpr
ch_off[i + 1] <- end_bal[i]*co / 12
end_bal[i + 1] <- end_bal[i] + pur[i + 1] - pmt[i + 1] - ch_off[i + 1]
}
amort <- data.frame(period, fin, pur, pmt, ch_off, end_bal)
这是(正确的)输出:
print(amort,row.names=FALSE)
period fin pur pmt ch_off end_bal
0 0.0000 0.0000 0.0000 0.00000 10000.000
1 166.6667 900.0000 1000.0000 83.33333 9816.667
2 163.6111 883.5000 981.6667 81.80556 9636.694
3 160.6116 867.3025 963.6694 80.30579 9460.022
4 157.6670 851.4020 946.0022 78.83351 9286.588
5 154.7765 835.7929 928.6588 77.38823 9116.334
6 151.9389 820.4700 911.6334 75.96945 8949.201
7 149.1534 805.4281 894.9201 74.57668 8785.132
8 146.4189 790.6619 878.5132 73.20944 8624.072
解决方案
没那么难,一旦你停止思考 Excel 的方式(我在 5-6 个月前开始 R 时也遇到了类似的问题,这就是为什么建议你)。您只需要将逻辑转换为数学方式。
- 实际上,您的月度/期刊
payment
包含三个项目,,pur
仅取决于以前的余额。pmt
ch_off
- 因此,如果我们计算
(mpr + co/12 - npr)
每个时期,我们payment
就可以计算出来。 period
从这里开始就更容易了0
,我们可以使用数学公式^
来计算end_bal
每个period
.- 此后,其余值很容易计算。
BaseR 版本
n_periods <- 8
begin_bal <- 10000
yld <- .20
npr <- .09
mpr <- .10
co <- .10
amort <- data.frame(period = seq(0, n_periods, 1))
amort$end_bal <- begin_bal * (1 - (mpr + co/12 - npr))^amort$period
amort$fin <- c(0, (amort$end_bal * yld/12)[-nrow(amort)])
amort$pur <- c(0, (amort$end_bal * npr)[-nrow(amort)])
amort$pmt <- c(0, (amort$end_bal * mpr)[-nrow(amort)])
amort$ch_off <- c(0, (amort$end_bal * co/12)[-nrow(amort)])
amort
#> period end_bal fin pur pmt ch_off
#> 1 0 10000.000 0.0000 0.0000 0.0000 0.00000
#> 2 1 9816.667 166.6667 900.0000 1000.0000 83.33333
#> 3 2 9636.694 163.6111 883.5000 981.6667 81.80556
#> 4 3 9460.022 160.6116 867.3025 963.6694 80.30579
#> 5 4 9286.588 157.6670 851.4020 946.0022 78.83351
#> 6 5 9116.334 154.7765 835.7929 928.6588 77.38823
#> 7 6 8949.201 151.9389 820.4700 911.6334 75.96945
#> 8 7 8785.132 149.1534 805.4281 894.9201 74.57668
#> 9 8 8624.072 146.4189 790.6619 878.5132 73.20944
dplyr 版本
n_periods <- 8
begin_bal <- 10000
yld <- .20
npr <- .09
mpr <- .10
co <- .10
library(dplyr)
seq(0, n_periods, 1) %>% as.data.frame() %>%
setNames('period') %>%
mutate(end_bal = begin_bal * (1 - (mpr + co/12 - npr))^period,
payment = -1 * c(0, diff(end_bal)),
fin = c(0, (end_bal * yld/12)[-nrow(.)]),
pur = c(0, (end_bal * npr)[-nrow(.)]),
pmt = c(0, (end_bal * mpr)[-nrow(.)]),
ch_off = c(0, (end_bal * co/12)[-nrow(.)]))
#> period end_bal payment fin pur pmt ch_off
#> 1 0 10000.000 0.0000 0.0000 0.0000 0.0000 0.00000
#> 2 1 9816.667 183.3333 166.6667 900.0000 1000.0000 83.33333
#> 3 2 9636.694 179.9722 163.6111 883.5000 981.6667 81.80556
#> 4 3 9460.022 176.6727 160.6116 867.3025 963.6694 80.30579
#> 5 4 9286.588 173.4337 157.6670 851.4020 946.0022 78.83351
#> 6 5 9116.334 170.2541 154.7765 835.7929 928.6588 77.38823
#> 7 6 8949.201 167.1328 151.9389 820.4700 911.6334 75.96945
#> 8 7 8785.132 164.0687 149.1534 805.4281 894.9201 74.57668
#> 9 8 8624.072 161.0608 146.4189 790.6619 878.5132 73.20944
由reprex 包于 2021-05-13 创建 (v2.0.0 )
注意创建的额外列payment
也可以删除
seq(0, n_periods, 1) %>% as.data.frame() %>%
setNames('period') %>%
mutate(end_bal = begin_bal * (1 - (mpr + co/12 - npr))^period,
fin = c(0, (end_bal * yld/12)[-nrow(.)]),
pur = c(0, (end_bal * npr)[-nrow(.)]),
pmt = c(0, (end_bal * mpr)[-nrow(.)]),
ch_off = c(0, (end_bal * co/12)[-nrow(.)]))
period end_bal fin pur pmt ch_off
1 0 10000.000 0.0000 0.0000 0.0000 0.00000
2 1 9816.667 166.6667 900.0000 1000.0000 83.33333
3 2 9636.694 163.6111 883.5000 981.6667 81.80556
4 3 9460.022 160.6116 867.3025 963.6694 80.30579
5 4 9286.588 157.6670 851.4020 946.0022 78.83351
6 5 9116.334 154.7765 835.7929 928.6588 77.38823
7 6 8949.201 151.9389 820.4700 911.6334 75.96945
8 7 8785.132 149.1534 805.4281 894.9201 74.57668
9 8 8624.072 146.4189 790.6619 878.5132 73.20944
dplyr::lag
也可以使用
seq(0, n_periods, 1) %>% as.data.frame() %>%
setNames('period') %>%
mutate(end_bal = begin_bal * (1 - (mpr + co/12 - npr))^period,
fin = lag(end_bal, default = 0) * yld/12,
pur = lag(end_bal, default = 0) * npr,
pmt = lag(end_bal, default = 0) * mpr,
ch_off = lag(end_bal, default = 0) * co/12)
推荐阅读
- c++ - 直接在类外调用构造函数会隐式创建一个对象吗?
- c++ - 哈希函数中对 c_str() 与 const char* 的函数调用
- powershell - Start-Process -WindowStyle Maximized 不会最大化窗口
- java - 在java中按升序对数组进行排序
- assembly - 更改地址在堆栈中的变量
- python - NoReverseMatch 在 /blog/2018/
- python - 如何将我的数据框中的两列添加到 np.array
- javascript - 如何使用 Javascript 将我的 Json 翻译成 HTML?
- html - 移动设备上的网页视图 - 只有上半部分正确显示?
- amazon-web-services - Webpack 4 + Jest + Babel 7 (+AWS Lambda):测试在本地通过,部署到 AWS Lambda 时出错