寻求比SLSQP更快的NLP优化算法(带约束极小化问题)
问题分析与解决方案
先修正代码中的明显错误
你代码里有个直接的bug:minimize的fun参数写的是er,但你定义的目标函数是obj,运行时会报错,得改成fun=obj。
思路一:将问题转化为线性规划(LP)问题
你认为约束c3的绝对值无法转LP,但其实绝对值约束可以通过引入辅助变量线性化,这样就能用专门的LP求解器,速度比SLSQP快得多(尤其你有750个变量的规模)。具体做法:
- 对每个
x_i,设u_i = |x_i|,那么约束c3sum(|x_i|)=2就转化为sum(u_i)=2,同时添加u_i >= x_i和u_i >= -x_i两个线性约束 - 约束c1
|sum(x_i*var1_i)| <= 0.05,拆成两个线性不等式:sum(x_i*var1_i) <= 0.05和-sum(x_i*var1_i) <= 0.05
转化后整个问题就是标准LP,目标等价于最大化sum(x_i*pred_i)(原问题是最小化-sum(...)),约束全是线性的。
线性化后的LP代码示例
import pandas as pd import numpy as np from scipy.optimize import linprog # 生成数据 df = pd.DataFrame(np.random.rand(750,3),columns=['pred','var1','start']) n = len(df) # 目标函数系数:转为最小化 -sum(x_i*pred_i) c = -df['pred'].values # 扩展变量:x_i + u_i,共2n个变量 c = np.concatenate([c, np.zeros(n)]) # 等式约束 A_eq = [] b_eq = [] # 约束1:sum(x_i) = 0(原c2的eq约束) A_eq.append(np.concatenate([np.ones(n), np.zeros(n)])) b_eq.append(0.0) # 约束2:sum(u_i) = 2(原c3的eq约束) A_eq.append(np.concatenate([np.zeros(n), np.ones(n)])) b_eq.append(2.0) # 不等式约束 A_ineq = [] b_ineq = [] # u_i >= x_i → -x_i + u_i >= 0 for i in range(n): row = np.zeros(2*n) row[i] = -1 row[n+i] = 1 A_ineq.append(row) b_ineq.append(0.0) # u_i >= -x_i → x_i + u_i >= 0 for i in range(n): row = np.zeros(2*n) row[i] = 1 row[n+i] = 1 A_ineq.append(row) b_ineq.append(0.0) # sum(x_i*var1_i) <= 0.05 A_ineq.append(np.concatenate([df['var1'].values, np.zeros(n)])) b_ineq.append(0.05) # -sum(x_i*var1_i) <= 0.05 A_ineq.append(np.concatenate([-df['var1'].values, np.zeros(n)])) b_ineq.append(0.05) # 变量边界:x_i ∈ [-1,3],u_i >=0 bounds = [(-1, 3) for _ in range(n)] + [(0, None) for _ in range(n)] # 求解LP(用highs算法,高效处理大规模问题) sol = linprog(c, A_ub=A_ineq, b_ub=b_ineq, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method='highs') # 提取x的解 x_sol = sol.x[:n]
思路二:更快的NLP算法
如果不想转LP,可换用更高效的NLP求解器:
- trust-constr:scipy自带的约束优化算法,针对大规模平滑问题,性能优于SLSQP
- COBYLA:无需计算梯度,处理约束优化的速度可能更快,精度稍低
- IPOPT:第三方大规模NLP求解器,需搭配Pyomo等建模库,性能远优于scipy自带算法
内容的提问来源于stack exchange,提问作者lara_toff
相关产品推荐
相关产品推荐

