我是 R 和优化的新手。我试图优化分为 3 个区域的 5 个月小麦收获期的总收入。我想引入两个约束:
-在每个时间步我只允许在一个区域收获
-开放区域的收获率 (HR) 在 0.1 到 0.5 之间(当然,另外两个区域的收获率为 0)
因此,我想要一种优化,1. 找到要开放的区域,2. 为其分配一个 HR,从而在每个时间步最大化收入。
到目前为止,我已经能够引入带有随机惩罚参数的惩罚函数。但是,它仅适用于很短的时间段(例如,5 或 10 个月)。当我将时间增加到 15 个月或更长时间时,就会为某些时间步长打开两个或三个补丁。 我如何才能确保每月只打开一个补丁并在更长的时间内开放?
我在这里粘贴一个玩具示例。任何建议将不胜感激!
r=3
c=10
biomass = matrix (runif(r*c , 50, 100), r, c)
price = matrix(runif(r*c, 5, 10), r, c)
yield = matrix(NA, r, c)
revenues = yield
value = rep(NA, c)
crop = function(HR){
HR = matrix(HR, r, c)
for (i in 1:c){
if (i<c){
yield[,i] = biomass[,i] * HR[,i]
revenues[,i] = yield[,i] * price[,i]
biomass[,i+1] = biomass[,i] - yield[,i]
value[i] = sum(revenues[,i])
}else{
yield[,i] = biomass[,i] * HR[,i]
revenues[,i] = yield[,i] * price[,i]
value[i] = sum(revenues[,i])
output=sum(value)
}
}
return(output)
}
penalty <- function(HR) {
HR1 <- matrix(HR, r, c)
penaltyfun = 12000 * ((HR1[1,]*HR1[3,])^2 + (HR1[1,]*HR1[2,])^2 + (HR1[2,]*HR1[3,])^2)
mainfun <- crop(HR1-penaltyfun)
return(mainfun)
}
HR= matrix(0.1, r, c)
test = optim(par=as.vector(HR), fn=penalty, lower=0, upper=0.5,
control = list(fnscale = -1),
method = 'L-BFGS-B')
options(max.print=100000)
matrix(test$par, r, c)
答案 0 :(得分:1)
当你拿着锤子时,一切都开始看起来像钉子。
根据您告诉我们的内容和您的代码,您正在解决这个问题:
观察 1:除非您引入其他限制,否则没有理由让收获率小于最大收获面积。1
观察 2:由于收获量与后续生物量或价格无关,您将获得 maximum_total_revenue = sum(max_revenue(step))
观察 3: 由于您一次只能从一个田地中收获,您只需寻找 max(revenue1,income2、收入3),无需进一步优化。
观察 1、2 和 3 的结果:不要使用 optim
,这是一种矫枉过正。只需查看时间序列,计算最大值并将它们相加即可。
可能是,您发布的案例只是一个可供学习的示例。在这种情况下,可能需要使用 optim
for。在您的情况下,optim
函数最大化了作物(HR1,HR2,HR3) - 惩罚(HR1,HR2,HR3)。
观察 1:由于您的 HR < 1,您实际上是在通过平方项来射击自己,因为在这种情况下 (HR1[1,]*HR1[3,])^2 < (HR1[1,]*HR1[3,])
。2由于如果超过一个 HR 不为零,您正试图获得尽可能大的惩罚,您可能不想这样做。
观察 2: 将惩罚计算为 crop(HR1-penaltyfun)
有点奇怪。问题是你突然计算出一些负的作物率,而在试图计算它时事情会崩溃。我不太确定为什么会发生这种情况,因为我不太了解 optim
的内部。所以我建议惩罚为crop(HR1) - penaltyfun
。从外行人的角度来看,这更有意义 - 我们不会单独惩罚作物产量和收入,我们只是增加了打破限制的惩罚。
所以我们需要做的最后一件事是确保惩罚足够大,以阻止优化器一次收获两个补丁。这什么时候可以发生?
如果H1 * H2 * penalty_constant / columns < revenue(H1) + revenue(H2)
。例如。如果违反规则时给定步骤的收入大于遵守规则时的收入。3
如何打击这种公然违反规则的行为?
通过调整penalty_constant。您希望常量足够大以保证 “只有一个收割机” 策略,但又不会大到让优化器陷入恐慌:“收割是可怕的,我宁愿不收割因为惩罚是如此之大”。
penalty <- function(HR) {
HR1 <- matrix(HR, r, c)
penaltyfun = 100 * c * ((HR1[1,]*HR1[3,]) + (HR1[1,]*HR1[2,]) + (HR1[2,]*HR1[3,]))
mainfun <- crop(HR1) - sum(penaltyfun)
return(mainfun)
}
这个对我来说效果很好。不过,它可能仍然需要一些调整。特别是如果您想为每个非零结果值获得不同于 HR_max 的结果。
1将需要非线性约束 - 因为否则 HR 将是 0 或 0.5,具体取决于是否值得收获。
2 0.52 = 0.25 < 0.5
3 优化器告诉我们类似的事情:你确定你不想为了这一天偷邻居的收割机吗?奖励是值得的。