Scipy minimize添加b₁<b₂<b₃约束报错,求解决方案
问题:添加b₁<b₂<b₃约束时scipy.minimize触发TypeError错误
我正在编写最小化程序,通过拟合b₁、b₂、b₃,寻找预测值r与实际值x之间的最小平方和误差。使用scipy.optimize.minimize函数,已为三个变量设置有效边界,但添加b₁<b₂<b₃约束时触发错误:
TypeError: numpy boolean subtract, the - operator, is not supported, use the bitwise_xor, the ^ operator, or the logical_xor function instead
无约束时拟合结果符合预期,但部分数据点无法满足b₁<b₂<b₃要求,需要解决约束添加问题。
原代码
import numpy as np import pandas as pd import sys import math import numpy as np from scipy.optimize import curve_fit import os from scipy.optimize import minimize def psd_fun(c_s): b_1 = c_s[0] b_2 = c_s[1] b_3 = c_s[2] a = np.arange(-1.0, 1.01, 0.10) b = np.linspace(-1.0, 5.0, 40) c = [] x=282.335 p_1 = 0.109 p_2 = 0.102 p_3 = 0.789 pt = 0.440 d1=[] d2=[] d3=[] d12=[] d22=[] d32=[] for i in b: z=10**i c += [z] for i in c: d1 += [p_1*(1-math.exp(-(i/b_1)))*pt] d2 += [p_2 * (1 - math.exp(-(i / b_2))) * pt] d3 += [p_3 * (1 - math.exp(-(i / b_3))) * pt] for i in range(1,len(d3),1): d12 += [((d1[i]-d1[i-1])/(p_1*pt)*c[i])] d22 +=[(d2[i]-d2[i-1])/(p_2*pt)*c[i]] d32 +=[(d3[i]-d3[i-1])/(p_3*pt)*c[i]] r = sum(d12)*p_1*pt+sum(d22)*p_2*pt+sum(d32)*p_3*pt r1 = (r-x)**2 return r1 cons = ({'type': 'ineq', 'fun': lambda c_s: np.array([c_s[0] <= c_s[1]])}, {'type': 'ineq', 'fun': lambda c_s: np.array([c_s[1] <= c_s[2]])}) bnds = ((0.1, 2.5), (15, 500), (400, 10000)) min_res = minimize(psd_fun, [2.5,276,435], bounds = bnds, constraints=cons) print(min_res)
错误原因
scipy.optimize.minimize的不等式约束(type='ineq')要求约束函数返回数值型数组/标量,且返回值需≥0。原代码中直接返回布尔数组(c_s[0] <= c_s[1]生成True/False),优化器在后续数值运算中会尝试对布尔值执行减法等操作,触发类型错误。
修正方案
将布尔比较转换为数值型的差值表达式,确保约束函数返回≥0的数值:
- 对于
b₁ ≤ b₂,等价于b₂ - b₁ ≥ 0,约束函数返回c_s[1] - c_s[0] - 对于
b₂ ≤ b₃,等价于b₃ - b₂ ≥ 0,约束函数返回c_s[2] - c_s[1]
如果需要严格小于(b₁ < b₂ < b₃),可以在差值中加上一个极小的正数(如1e-8),避免数值精度问题导致变量相等的情况。
修正后的代码(仅修改约束部分)
# 修正约束定义 cons = ({'type': 'ineq', 'fun': lambda c_s: c_s[1] - c_s[0]}, # b2 - b1 >=0 → b1 <= b2 {'type': 'ineq', 'fun': lambda c_s: c_s[2] - c_s[1]}) # b3 - b2 >=0 → b2 <= b3 # 若需要严格小于,可改为: # cons = ({'type': 'ineq', 'fun': lambda c_s: c_s[1] - c_s[0] - 1e-8}, # {'type': 'ineq', 'fun': lambda c_s: c_s[2] - c_s[1] - 1e-8}) bnds = ((0.1, 2.5), (15, 500), (400, 10000)) min_res = minimize(psd_fun, [2.5,276,435], bounds = bnds, constraints=cons) print(min_res)
验证结果
修改后运行代码,约束会正常生效,不会触发类型错误。以你的无约束结果为例,其本身已经满足b₁<b₂<b₃,添加约束后会得到类似的收敛结果,同时确保所有拟合结果都符合b₁≤b₂≤b₃(或严格小于)的要求。
内容的提问来源于stack exchange,提问作者dpp1992
相关产品推荐
相关产品推荐

