当我尝试使用 for 循环设置约束时,Scipy 优化未运行

Posted

技术标签:

【中文标题】当我尝试使用 for 循环设置约束时,Scipy 优化未运行【英文标题】:Scipy Optimization Not Running when I try to set constraints using a for loop 【发布时间】:2018-01-11 11:33:45 【问题描述】:

我试图最小化目标函数,同时使用 for 循环设置约束,使得 x1 = x2 = ... xn。但是,优化似乎不起作用。 IE。结束 x 仍然等于初始 x。我收到一条错误消息“LSQ 子问题中的奇异矩阵 C”。

covariance_matrix = np.matrix([[0.159775519, 0.022286316, 0.00137635, -0.001861736],
                     [0.022286316, 0.180593862, -5.5578e-05, 0.00451056], 
                     [0.00137635, -5.5578e-05, 0.053093075, 0.02240866], 
                     [-0.001861736, 0.00451056, 0.02240866, 0.053778594]]) 

x0 = np.matrix([0.2,0.2,0.3,0.4])


fun = lambda x: x.dot(covariance_matrix).dot(x.transpose())
cons = np.array([])
for i in range(0,x0.size-1):
    con = 'type': 'eq', 'fun': lambda x:  x[i] - x[i+1]    
    cons = np.append(cons, con)

con = 'type': 'eq', 'fun': lambda x:  sum(x)-1   
cons = np.append(cons, con) 

solution = minimize(fun,x0,method='SLSQP',constraints = cons)


solution message:   Singular matrix C in LSQ subproblem
solution status:   6
solution success:   False

但是如果我一个一个地附加约束,那么它就可以完美地工作,这意味着结果给了我 x1 = x2 = x3 = x4

con1 = 'type': 'eq', 'fun': lambda x:  sum(x)-1   
con2 = 'type': 'eq', 'fun': lambda x:  x[1]-x[0]   
con3 = 'type': 'eq', 'fun': lambda x:  x[2]-x[1]   
con4 = 'type': 'eq', 'fun': lambda x:  x[3]-x[2]   
cons = np.append(cons, con1) 
cons = np.append(cons, con2) 
cons = np.append(cons, con3) 
cons = np.append(cons, con4) 

solution message:   Optimization terminated successfully.
solution status:   0
solution success:   True

【问题讨论】:

"...优化似乎不起作用。即结束x仍然等于初始x。"无需猜测它“没有'似乎不起作用'。 solution 对象告诉通过将 solution.success 设置为 False 不起作用。原因的简短描述在solution.message 中。致电minimize() 后,请务必检查solution.success。您能否在调用minimize() 后编辑问题以显示solution.successsolution.statussolution.message 谢谢沃伦!我已经编辑了最初的问题。看来我遇到了“LSQ 子问题中的奇异矩阵 C”问题。你知道这是从哪里来的吗? 看起来该消息是从底层 Fortran 求解器的源代码中复制的。不幸的是,我在minimizefmin_slsqp 的文档字符串中没有看到“矩阵C”的描述,所以有人必须深入研究Fortran 代码(至少是Fortran 代码中的cmets)才能弄清楚C是什么。 scipy中的代码是slsqp_optmz.f. 不过,我要补充一点,你的等式约束唯一地确定了解决方案——在你的问题中没有什么可以优化的。 沃伦,你能详细说明一下吗?我认为设置是最小化目标函数。我的主要问题是,如果我一一附加这些约束,那么它就可以工作。但如果我使用循环,则不会。 【参考方案1】:

(注意:虽然细节不同,但这个问题和Scipy.optimize.minimize SLSQP with linear constraints fails的问题差不多)

你的循环是

for i in range(0,x0.size-1):
    con = 'type': 'eq', 'fun': lambda x:  x[i] - x[i+1]    
    cons = np.append(cons, con)

问题是在 lambda 表达式中使用了i。 Python closures are "late binding"。这意味着调用函数时使用的i 的值与创建函数时的i 的值不同。在循环之后,i 的值为 2,因此循环中创建的所有函数计算的表达式为 x[2] - x[3]。 (这也解释了错误消息中提到的“奇异矩阵 C”。)

解决此问题的一种方法是将i 设为默认值为当前i 的lambda 表达式的参数:

    con = 'type': 'eq', 'fun': lambda x, i=i:  x[i] - x[i+1]

【讨论】:

完美答案! 我非常感谢您的回答。我是 SciPy 的新手,对此我很头疼!非常感谢@Warren @dickli2119 您可以通过勾选箭头来接受答案。

以上是关于当我尝试使用 for 循环设置约束时,Scipy 优化未运行的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中输出绘图时迭代线性回归(SciPy 和 MatPlotLib)

scipy.minimize 如何处理 NaN?

Python中的约束最小二乘估计

如何通过childNodes使用for循环?

如何使用 pygame 执行秒/毫秒的 for 循环?

当我没有收到手动运行代码时,在 Python for 循环中收到 KeyError