如何对多个变量正确使用 minimize from scipy?
How to use minimize from scipy correctly with multible variables?
我有五个变量要服从 scipy.optimize.minimize
以便根据 A
、B
、C
找到我正在寻求的解决方案、D
和 E
。首先,我从 scipy
导入 minimize
并定义了初始猜测(基于实验室实验,因此它们应该是有效的)。
from scipy.optimize import minimize
A0 = 1.90
B0 = 6.40
C0 = 11.7
D0 = 3.70
E0 = 2.50
ABCDE0 = [A0, B0, C0, D0, E0]
其次,我定义了构成 objective 函数的各个函数,方便地命名为 Objective
。我也尝试过将 F
、G
、H
和 I
组合成一个函数,但没有成功,所以我决定暂时这样。
def F(abcde):
a, b, c, d, e = abcde
return c - (b ** 2) / (a - e)
def G(abcde):
a, b, c, d, e = abcde
return (4 * e * ((a - e) * c - b ** 2)) / (a * c - b ** 2)
def H(abcde):
a, b, c, d, e = abcde
return b / (2 * (a - e))
def I(abcde):
a, b, c, d, e = abcde
return (2 * e * b) / (a * c - b ** 2)
def Objective(abcde):
return (F(abcde) / G(abcde)) / (H(abcde) / I(abcde))
第三,为了简单起见,我将constraint
(即(F/G)/(H/I)=1
)和名为bnds
的边界定义为初始猜测的+/- 10%
。
def constraint(x):
F = x[0]
G = x[1]
H = x[2]
I = x[3]
return (F / G) / (H / I) - 1
con = {'type': 'eq', 'fun': constraint1}
min_per = 0.9
max_per = 1.1
bnds = ((A0*min_per, A0*max_per), (B0*min_per, B0*max_per),
(C0*min_per, C0*max_per), (D0*min_per, D0*max_per),
(E0*min_per, E0*max_per))
第四,也是最后,minimize
为我提供了一个名为 sol
的解决方案。
sol = minimize(Objective, ABCDE0, method='SLSQP', bounds=bnds, constraints=con1, options={'disp':True})
如果 sol 由 print(sol)
打印,将出现以下消息。
Positive directional derivative for linesearch (Exit mode 8)
Current function value: 1.0
Iterations: 18
Function evaluations: 188
Gradient evaluations: 14
fun: 1.0
jac: array([ 0.00000000e+00, 1.49011612e-08, -7.45058060e-09, 0.00000000e+00,
0.00000000e+00])
message: 'Positive directional derivative for linesearch'
nfev: 188
nit: 18
njev: 14
status: 8
success: False
x: array([ 2.09 , 5.76 , 10.53 , 4.07 , 2.50000277])
在我的新手看来,constraint
似乎是问题所在,但由于缺乏 minimize
的经验,我不确定。
- 我做错了什么?
- 为什么执行不成功?
- 在这种情况下,是否按照@fuglede 的建议使用
root_scalar
更好?
- 是否可以将所有单独的函数包含在一个函数中以避免弄乱?
请注意,D0
和 d
不包含在任何函数中,但作为五个自变量之一在事物的宏伟计划中很重要。
这里发生了几件事:
首先,出于个人喜好,我可能会将函数 F
、...、I
保留为具有多个输入以避免必须解压缩列表。 objective 函数确实需要一个列表作为它的参数;即你可以做类似
的事情
def F(a, b, c, d, e):
return c - (b ** 2) / (a - e)
...
def objective(abcde):
return (F(*abcde) / G(*abcde)) / (H(*abcde) / I(*abcde))
这就是风格。更重要的是,您的 constraint
方法不会完全按照您的意愿行事:据我了解,您想评估输入上的函数 F
, ..., I
,但是永远不会发生;相反,变量 F
的值(这是一个不幸的名字,因为它掩盖了函数的名称)最终只是 a
。相反,你会做类似
def constraint(x):
return (F(*x) / G(*x)) / (H(*x) / I(*x)) - 1
现在,constraint(x)
只不过是 objective(x) - 1
,因此您的约束最终表明您的 objective
在可行解中必须等于 1。这意味着实际上根本没有进行太多优化:任何可行的解决方案都是最优的。虽然先验的 minimize
确实会尝试为您找到一个可行的解决方案,但您可能会更幸运地尝试使用 scipy.optimize
的 root-finding capabilities 中的一些作为您想要的正在尝试找到函数 objective - 1
.
的根
现在终于,事实证明这很简单:你的函数 objective
在任何定义的地方都等于 1,所以 any 输入是一个可行的解决方案:首先,通过写 F = ((a-e)c - (b**2))/(a-e)
,注意 (a*c-b**2) / (4*e*(a-e))
。那么,(F/G)*I = (2*e*b)/(4*e*(a-e)) = b/(2*(a-e)) = H
,所以1 = (F/G)*(I/H) = (F/G)/(H/I)
.
我有五个变量要服从 scipy.optimize.minimize
以便根据 A
、B
、C
找到我正在寻求的解决方案、D
和 E
。首先,我从 scipy
导入 minimize
并定义了初始猜测(基于实验室实验,因此它们应该是有效的)。
from scipy.optimize import minimize
A0 = 1.90
B0 = 6.40
C0 = 11.7
D0 = 3.70
E0 = 2.50
ABCDE0 = [A0, B0, C0, D0, E0]
其次,我定义了构成 objective 函数的各个函数,方便地命名为 Objective
。我也尝试过将 F
、G
、H
和 I
组合成一个函数,但没有成功,所以我决定暂时这样。
def F(abcde):
a, b, c, d, e = abcde
return c - (b ** 2) / (a - e)
def G(abcde):
a, b, c, d, e = abcde
return (4 * e * ((a - e) * c - b ** 2)) / (a * c - b ** 2)
def H(abcde):
a, b, c, d, e = abcde
return b / (2 * (a - e))
def I(abcde):
a, b, c, d, e = abcde
return (2 * e * b) / (a * c - b ** 2)
def Objective(abcde):
return (F(abcde) / G(abcde)) / (H(abcde) / I(abcde))
第三,为了简单起见,我将constraint
(即(F/G)/(H/I)=1
)和名为bnds
的边界定义为初始猜测的+/- 10%
。
def constraint(x):
F = x[0]
G = x[1]
H = x[2]
I = x[3]
return (F / G) / (H / I) - 1
con = {'type': 'eq', 'fun': constraint1}
min_per = 0.9
max_per = 1.1
bnds = ((A0*min_per, A0*max_per), (B0*min_per, B0*max_per),
(C0*min_per, C0*max_per), (D0*min_per, D0*max_per),
(E0*min_per, E0*max_per))
第四,也是最后,minimize
为我提供了一个名为 sol
的解决方案。
sol = minimize(Objective, ABCDE0, method='SLSQP', bounds=bnds, constraints=con1, options={'disp':True})
如果 sol 由 print(sol)
打印,将出现以下消息。
Positive directional derivative for linesearch (Exit mode 8)
Current function value: 1.0
Iterations: 18
Function evaluations: 188
Gradient evaluations: 14
fun: 1.0
jac: array([ 0.00000000e+00, 1.49011612e-08, -7.45058060e-09, 0.00000000e+00,
0.00000000e+00])
message: 'Positive directional derivative for linesearch'
nfev: 188
nit: 18
njev: 14
status: 8
success: False
x: array([ 2.09 , 5.76 , 10.53 , 4.07 , 2.50000277])
在我的新手看来,constraint
似乎是问题所在,但由于缺乏 minimize
的经验,我不确定。
- 我做错了什么?
- 为什么执行不成功?
- 在这种情况下,是否按照@fuglede 的建议使用
root_scalar
更好? - 是否可以将所有单独的函数包含在一个函数中以避免弄乱?
请注意,D0
和 d
不包含在任何函数中,但作为五个自变量之一在事物的宏伟计划中很重要。
这里发生了几件事:
首先,出于个人喜好,我可能会将函数 F
、...、I
保留为具有多个输入以避免必须解压缩列表。 objective 函数确实需要一个列表作为它的参数;即你可以做类似
def F(a, b, c, d, e):
return c - (b ** 2) / (a - e)
...
def objective(abcde):
return (F(*abcde) / G(*abcde)) / (H(*abcde) / I(*abcde))
这就是风格。更重要的是,您的 constraint
方法不会完全按照您的意愿行事:据我了解,您想评估输入上的函数 F
, ..., I
,但是永远不会发生;相反,变量 F
的值(这是一个不幸的名字,因为它掩盖了函数的名称)最终只是 a
。相反,你会做类似
def constraint(x):
return (F(*x) / G(*x)) / (H(*x) / I(*x)) - 1
现在,constraint(x)
只不过是 objective(x) - 1
,因此您的约束最终表明您的 objective
在可行解中必须等于 1。这意味着实际上根本没有进行太多优化:任何可行的解决方案都是最优的。虽然先验的 minimize
确实会尝试为您找到一个可行的解决方案,但您可能会更幸运地尝试使用 scipy.optimize
的 root-finding capabilities 中的一些作为您想要的正在尝试找到函数 objective - 1
.
现在终于,事实证明这很简单:你的函数 objective
在任何定义的地方都等于 1,所以 any 输入是一个可行的解决方案:首先,通过写 F = ((a-e)c - (b**2))/(a-e)
,注意 (a*c-b**2) / (4*e*(a-e))
。那么,(F/G)*I = (2*e*b)/(4*e*(a-e)) = b/(2*(a-e)) = H
,所以1 = (F/G)*(I/H) = (F/G)/(H/I)
.