如何使用 R 的 optimize、optim 函数等来查找提供特定返回值的函数输入?
How do I use R's optimize, optim functions, etc. to find the function input that provides a specific returned value?
我试图找到一个函数输入值(标量),当它与其他三个已知矢量参数结合时,创建第四个矢量,该矢量在特定矢量元素处(而不是之前)精确地减小到零。
第四个向量包含计算出的投资组合余额,每个向量元素都是一年。我希望投资组合余额在投资者去世那一年的投资组合余额中准确减少到零(该年份在已知向量参数之一中指定)。我想通过找到初始投资组合值来实现这一点,该初始投资组合值会导致该向量元素在死亡年份立即等于零。
(注意:在 Excel 中,这可以使用 Goal Seek 工具通过更改初始投资组合值将特定投资组合平衡元素(年份)设置为零来完成。)
我已经尝试了 optim 和 optimize 但最后尝试了下面的脚本。优化后的初始投资组合价值始终等于约束最大值。
如有任何帮助,我们将不胜感激。这两天一直在拔头发
f1 <- function(init,spendV,returnV,stateV) {
# create a vector that equals an initial portfolio value (init) and sets subsequent vector elements
# equal to the previous portfolio balance minus an amount of spending and then applies a market return rate.
# Portfolio balance can never fall below zero
# When the state vector element = 4, the investor died in the previous period
endState <- which (stateV == 4)
portfoliobal <- rep(0,length(spendV))
portfoliobal[1] <- (init - spendV[1]) * returnV[1]
for (i in (2:length(spendV))) {
portfoliobal[i] <- max(0,(portfoliobal[i-1] - spendV[i]) * returnV[i])
}
# the function returns the portfolio balance when the investor dies
return(portfoliobal[endState])
}
# spending, market growth rates, and the period of death are given vectors
spendV <- c(97719.19,97737.92,102649.4,98669.15,78108.44,58105.49,51710.02,53267.12,
39982.34,21070,22439.68,21375.4,15613.45,10826.54,9333.82,7808.239,
8737.435,8382.001,7267.976,6534.688,5129.403,5026.947,4931.132,5468.401,
5033.245,5195.273,5199.938,4854.684,5039.221,3757.753,1822.97,1202.24,
1237.238,965.111,1051.235,906.4884,1110.66,1018.127,500.788,538.2703,
584.5545,599.1832,575.2254,640.8828,604.0179,781.878,595.9795,625.5037,
615.471,667.4227)
init <- 1000000
returnV <- c(0.9347388,1.170053,1.204515,0.9572276,1.044682,0.9229759,1.110595,0.9299398,
1.161509,1.053207,1.058104,0.8997761,1.000342,1.353597,1.031785,1.121795,0.8745584,
1.05637,1.180234,0.9795393,0.9137375,0.772738,1.021843,0.9697467,1.055284,0.9182615,
0.9662726,1.105152,1.099005,0.9195565,0.895424,0.9226368,1.196467,1.085768,0.9529325,
1.485245,0.9124764,0.8978044,0.8021779,0.9064698,1.034353,0.9914232,0.742632,
0.9308539,0.9683604,0.9325817,1.000051,1.145982,1.018012,1.127159)
stateV <- c(3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
cat("\n\nCritical vector element= ",which(stateV == 4))
# the critical vector element is the portfolio balance at death
# I experiment with different inital portfolio values and find that portfolio balance[34] approaches zero
# when initial portfolio balance is about 710,000
f1value <- f1(init=1000000,spendV,returnV,stateV)
cat ("\n\nf1value for critical vector element",which(stateV == 4)," when inital value = 1,000,000: ",f1value)
f1value <- f1(init=800000,spendV,returnV,stateV)
cat ("\n\nf1value for critical vector element",which(stateV == 4)," when inital value = 800,000: ",f1value)
f1value <- f1(init=710000,spendV,returnV,stateV)
cat ("\n\nf1value for critical vector element",which(stateV == 4)," when inital value = 710,000: ",f1value)
# I am trying to find the initial portfolio balance that leaves zero dollars in portfolio balance vector [34]
# ---- BUT not BEFORE portfolio balance [34]
# opt <- optimize(f1,c(0,10000000),spendV,returnV,stateV,maximum = FALSE)
回答
optim()
和 optimize()
都寻求最小值(默认情况下)。你想要一个零。您要查找的函数是 uniroot()
。这样做:
uniroot(f=f1, interval=c(1, 1e7), spendV=spendV, returnV=returnV, stateV=stateV)
#> $root
#> 703932.9
一些其他的东西
为了好玩,这里用矢量化符号重写了你的函数(我懒惰地省略了 returnV
和 spendV
args):
f2 <- function(init, end=34) {
init*prod(returnV[1:end]) - sum(cumprod(returnV[end:1])*spendV[end:1])
}
uniroot(f2, c(1, 1e7))
#> $root
#> 703932.9
一般来说,如果您正在测试可能的解决方案,您可能会发现绘制一大堆解决方案更容易,而不是一次尝试一个并使用 cat()
报告结果。以下是我的处理方法:
x <- seq(1, 2e6, by=100000)
y <- f2(x, 34)
plot(x, y, pch=20)
abline(v=0, h=0)
最后一个想法:在您的函数 f1
中,如果用户输入 stateV=c(1,4,4)
,行 which(stateV==4)
可能 return 一个值向量。我猜你想要第一次出现“4”,你可以用 which(stateV==4)[1]
或 if(sum(stateV==4)>1) stop("Too many 4s!")
来完成。
我试图找到一个函数输入值(标量),当它与其他三个已知矢量参数结合时,创建第四个矢量,该矢量在特定矢量元素处(而不是之前)精确地减小到零。
第四个向量包含计算出的投资组合余额,每个向量元素都是一年。我希望投资组合余额在投资者去世那一年的投资组合余额中准确减少到零(该年份在已知向量参数之一中指定)。我想通过找到初始投资组合值来实现这一点,该初始投资组合值会导致该向量元素在死亡年份立即等于零。
(注意:在 Excel 中,这可以使用 Goal Seek 工具通过更改初始投资组合值将特定投资组合平衡元素(年份)设置为零来完成。)
我已经尝试了 optim 和 optimize 但最后尝试了下面的脚本。优化后的初始投资组合价值始终等于约束最大值。
如有任何帮助,我们将不胜感激。这两天一直在拔头发
f1 <- function(init,spendV,returnV,stateV) {
# create a vector that equals an initial portfolio value (init) and sets subsequent vector elements
# equal to the previous portfolio balance minus an amount of spending and then applies a market return rate.
# Portfolio balance can never fall below zero
# When the state vector element = 4, the investor died in the previous period
endState <- which (stateV == 4)
portfoliobal <- rep(0,length(spendV))
portfoliobal[1] <- (init - spendV[1]) * returnV[1]
for (i in (2:length(spendV))) {
portfoliobal[i] <- max(0,(portfoliobal[i-1] - spendV[i]) * returnV[i])
}
# the function returns the portfolio balance when the investor dies
return(portfoliobal[endState])
}
# spending, market growth rates, and the period of death are given vectors
spendV <- c(97719.19,97737.92,102649.4,98669.15,78108.44,58105.49,51710.02,53267.12,
39982.34,21070,22439.68,21375.4,15613.45,10826.54,9333.82,7808.239,
8737.435,8382.001,7267.976,6534.688,5129.403,5026.947,4931.132,5468.401,
5033.245,5195.273,5199.938,4854.684,5039.221,3757.753,1822.97,1202.24,
1237.238,965.111,1051.235,906.4884,1110.66,1018.127,500.788,538.2703,
584.5545,599.1832,575.2254,640.8828,604.0179,781.878,595.9795,625.5037,
615.471,667.4227)
init <- 1000000
returnV <- c(0.9347388,1.170053,1.204515,0.9572276,1.044682,0.9229759,1.110595,0.9299398,
1.161509,1.053207,1.058104,0.8997761,1.000342,1.353597,1.031785,1.121795,0.8745584,
1.05637,1.180234,0.9795393,0.9137375,0.772738,1.021843,0.9697467,1.055284,0.9182615,
0.9662726,1.105152,1.099005,0.9195565,0.895424,0.9226368,1.196467,1.085768,0.9529325,
1.485245,0.9124764,0.8978044,0.8021779,0.9064698,1.034353,0.9914232,0.742632,
0.9308539,0.9683604,0.9325817,1.000051,1.145982,1.018012,1.127159)
stateV <- c(3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
cat("\n\nCritical vector element= ",which(stateV == 4))
# the critical vector element is the portfolio balance at death
# I experiment with different inital portfolio values and find that portfolio balance[34] approaches zero
# when initial portfolio balance is about 710,000
f1value <- f1(init=1000000,spendV,returnV,stateV)
cat ("\n\nf1value for critical vector element",which(stateV == 4)," when inital value = 1,000,000: ",f1value)
f1value <- f1(init=800000,spendV,returnV,stateV)
cat ("\n\nf1value for critical vector element",which(stateV == 4)," when inital value = 800,000: ",f1value)
f1value <- f1(init=710000,spendV,returnV,stateV)
cat ("\n\nf1value for critical vector element",which(stateV == 4)," when inital value = 710,000: ",f1value)
# I am trying to find the initial portfolio balance that leaves zero dollars in portfolio balance vector [34]
# ---- BUT not BEFORE portfolio balance [34]
# opt <- optimize(f1,c(0,10000000),spendV,returnV,stateV,maximum = FALSE)
回答
optim()
和 optimize()
都寻求最小值(默认情况下)。你想要一个零。您要查找的函数是 uniroot()
。这样做:
uniroot(f=f1, interval=c(1, 1e7), spendV=spendV, returnV=returnV, stateV=stateV)
#> $root
#> 703932.9
一些其他的东西
为了好玩,这里用矢量化符号重写了你的函数(我懒惰地省略了 returnV
和 spendV
args):
f2 <- function(init, end=34) {
init*prod(returnV[1:end]) - sum(cumprod(returnV[end:1])*spendV[end:1])
}
uniroot(f2, c(1, 1e7))
#> $root
#> 703932.9
一般来说,如果您正在测试可能的解决方案,您可能会发现绘制一大堆解决方案更容易,而不是一次尝试一个并使用 cat()
报告结果。以下是我的处理方法:
x <- seq(1, 2e6, by=100000)
y <- f2(x, 34)
plot(x, y, pch=20)
abline(v=0, h=0)
最后一个想法:在您的函数 f1
中,如果用户输入 stateV=c(1,4,4)
,行 which(stateV==4)
可能 return 一个值向量。我猜你想要第一次出现“4”,你可以用 which(stateV==4)[1]
或 if(sum(stateV==4)>1) stop("Too many 4s!")
来完成。