如何解决GEKKO 中的约束非线性优化,目标函数与预期解不匹配
我有一个相当简单的约束非线性优化问题,在给定一些支出限制(保持总体支出不变,并将每个渠道的支出增加/减少多达 50%)和一个目标函数,即收入的情况下,最大化收入= 花费 * roi(其中 roi 是使用每个通道的 log-log 模型系数计算的)。
首先,该解决方案与我认为的最佳解决方案不符。另外,当将GEKKO建议的最优花费值放入目标函数时,这也与GEKKO给出的最优目标函数值不符。
如果上面的问题没有很好地表达出来,下面的示例代码应该可以解决这个问题......
有人知道我错过了什么吗?
代码如下:
from gekko import GEKKO
import numpy as np
import pandas as pd
df1 = pd.DataFrame({'channel': ['fb','tv','ppc'],'value': [5000,5000,5000],'alpha': [1.00,1.00,1.00],'beta': [0.03,0.02,0.01]
})
total_spend = df1['value'].sum()
m = GEKKO()
# Constraint parameters
spend_inc = 0.00
spend_dec = 0.00
channel_inc = 0.50
channel_dec = 0.50
channels = len(df1)
# Initialise decision variables
x = m.Array(m.Var,(channels),integer=True)
i = 0
for xi in x:
xi.value = df1['value'][i]
xi.lower = df1['value'][i] * (1 - channel_dec)
xi.upper = df1['value'][i] * (1 + channel_inc)
i += 1
# Initialise alpha
a = m.Array(m.Param,(channels))
i = 0
for ai in a:
ai.value = df1['alpha'][i]
i += 1
# Initialise beta
b = m.Array(m.Param,(channels))
i = 0
for bi in b:
bi.value = df1['beta'][i]
i += 1
# Initial global contraints
spend_min = total_spend * (1 - spend_dec)
spend_max = total_spend * (1 + spend_dec)
# Print out variabales
print(f'spend min: {spend_min}')
print(f'spend max: {spend_max}')
print('')
for i in range(0,channels):
print(f'x{i+1} value: {str(x[i].value)}')
print(f'x{i+1} lower: {str(x[i].lower)}')
print(f'x{i+1} upper: {str(x[i].upper)}')
print(f'x{i+1} alpha: {str(a[i].value)}')
print(f'x{i+1} beta: {str(b[i].value)}')
print('')
# Constraints
m.Equation(sum(x) >= spend_min)
m.Equation(sum(x) <= spend_max)
# Log-Log model
def roi(a,b,x):
roi = a + b * m.log(x[0])
roi = m.exp(roi[0])
return roi
# Objective function
m.Maximize(m.sum(x * roi(a,x)))
m.options.IMODE = 3
m.solve()
for i in range(0,channels):
print(f'x{i+1}: {str(x[i].value[0])}')
print('')
print(f'optimal solution: {str(m.options.objfcnval)}')
# THIS DOESN'T MATCH THE OBJECTIVE FUNCTION VALUE SUGGESTED BY GEKKO
opt = 0
for i in range(0,channels):
opt += x[i].value[0] * (np.exp((a[0].value[0] + b[i].value[0] * np.log(x[i].value[0]))))
print(f'optimal solution: {opt}')
# THIS IS THE EXPECETD SOLUTION,WHICH ALSO DOESN'T MATCH THE OBJECTIVE FUNCTION VALUE SUGGESTED BY GEKKO
7500 * np.exp(1.00 + 0.03 * np.log(7500)) + 5000 * np.exp(1.00 + 0.02 * np.log(5000)) + 2500 * np.exp(1.00 + 0.01 * np.log(2500))
解决方法
目标函数的定义方式存在问题。该问题的解决方法是在函数中一次使用 a[i]
、b[i]
、x[i]
一个。 Gekko 允许多个目标函数定义。最大化时,它转换为 min = -max
的最小化问题。因此最大化的目标是 -m.options.OBJFCNVAL
。
# Log-Log model
def roi(ai,bi,xi):
return m.exp(ai + bi * m.log(xi))
# Objective function
for i,xi in enumerate(x):
m.Maximize(xi * roi(a[i],b[i],x[i]))
它还有助于定义一个具有上限 sum_x
和下限 spend_max
的新变量 spend_min
。
# Constraints
sum_x = m.Var(lb=spend_min,ub=spend_max)
m.Equation(sum_x==m.sum(x))
这是完整的脚本。
from gekko import GEKKO
import numpy as np
import pandas as pd
df1 = pd.DataFrame({'channel': ['fb','tv','ppc'],'value': [5000,5000,5000],'alpha': [1.00,1.00,1.00],'beta': [0.03,0.02,0.01]
})
total_spend = df1['value'].sum()
m = GEKKO()
# Constraint parameters
spend_inc = 0.00
spend_dec = 0.00
channel_inc = 0.50
channel_dec = 0.50
channels = len(df1)
# Initialise decision variables
x = m.Array(m.Var,(channels),integer=True)
i = 0
for xi in x:
xi.value = df1['value'][i]
xi.lower = df1['value'][i] * (1 - channel_dec)
xi.upper = df1['value'][i] * (1 + channel_inc)
i += 1
# Initialise alpha
a = m.Array(m.Param,(channels))
i = 0
for ai in a:
ai.value = df1['alpha'][i]
i += 1
# Initialise beta
b = m.Array(m.Param,(channels))
i = 0
for bi in b:
bi.value = df1['beta'][i]
i += 1
# Initial global contraints
spend_min = total_spend * (1 - spend_dec)
spend_max = total_spend * (1 + spend_dec)
# Print out variabales
print(f'spend min: {spend_min}')
print(f'spend max: {spend_max}')
print('')
for i in range(0,channels):
print(f'x{i+1} value: {str(x[i].value)}')
print(f'x{i+1} lower: {str(x[i].lower)}')
print(f'x{i+1} upper: {str(x[i].upper)}')
print(f'x{i+1} alpha: {str(a[i].value)}')
print(f'x{i+1} beta: {str(b[i].value)}')
print('')
# Constraints
sum_x = m.Var(lb=spend_min,ub=spend_max)
m.Equation(sum_x==m.sum(x))
# Log-Log model
def roi(ai,x[i]))
m.options.IMODE = 3
m.solve()
for i in range(0,channels):
print(f'x{i+1}: {str(x[i].value[0])}')
print('')
print(f'optimal solution: {str(-m.options.objfcnval)}')
opt = 0
for i in range(0,channels):
opt += x[i].value[0] * (np.exp((a[i].value[0] \
+ b[i].value[0] \
* np.log(x[i].value[0]))))
print(f'optimal solution: {opt}')
# THIS IS THE EXPECTED SOLUTION
# IT NOW MATCHES THE OBJECTIVE FUNCTION VALUE SUGGESTED BY GEKKO
sol = 7500 * np.exp(1.00 + 0.03 * np.log(7500)) \
+ 5000 * np.exp(1.00 + 0.02 * np.log(5000)) \
+ 2500 * np.exp(1.00 + 0.01 * np.log(2500))
print(f'expected optimal solution: {sol}')
解决方案如下所示。
EXIT: Optimal Solution Found.
The solution was found.
The final value of the objective function is -50108.7613900549
---------------------------------------------------
Solver : IPOPT (v3.12)
Solution time : 9.499999985564500E-003 sec
Objective : -50108.7611889392
Successful solution
---------------------------------------------------
x1: 7500.0
x2: 4999.9999497
x3: 2500.0
optimal solution: 50108.761189
optimal solution: 50108.7611890521
expected optimal solution: 50108.76135441651
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。