如何为np.linalg.lstsq添加系数递增的约束条件?
解决方案:带递增+正值约束的最小二乘优化
这个问题本质是带线性不等式约束的最小二乘优化——既要最小化预测误差,又要保证x的元素严格递增且为正。np.linalg.lstsq确实无约束能力,scipy.optimize.nnls仅能处理非负约束,没法满足递增要求,咱们可以用scipy.optimize.minimize自定义约束来解决。
步骤1:明确约束条件
把需求转化为优化可识别的约束:
- 非负性:$x_i > 0$(实际优化中用$x_i \geq 1e-6$替代严格大于,避免数值不稳定)
- 递增性:$x_1 \leq x_2 \leq x_3 \leq x_4 \leq x_5$,等价于$x_{i+1} - x_i \geq 0$($i$从0到3)
步骤2:代码实现
导入依赖库
import numpy as np from scipy.optimize import minimize, nnls
定义问题数据
A = np.array([[4.737, 4.673, 4.664, 4.614, 4.614], [4.491, 4.377, 4.38 , 4.401, 4.406], [2.496, 1.689, 1.68 , 1.62 , 1.64 ], [3.461, 3.136, 2.816, 2.723, 2.551], [2.814, 2.4 , 2.444, 2.423, 2.436]]) y = np.array([4.90909091, 4.86363636, 1.86363636, 2.63636364, 3.63636364])
定义最小二乘目标函数
用误差的平方和作为优化目标:
def objective(x): return np.linalg.norm(A @ x - y, ord=2)**2 # 等价于sum((A@x - y)**2)
构造约束条件
递增约束
为每个相邻元素对构造“后项减前项≥0”的约束:
n = A.shape[1] incr_constraints = [] for i in range(n-1): coeffs = np.zeros(n) coeffs[i] = -1 coeffs[i+1] = 1 incr_constraints.append({'type': 'ineq', 'fun': lambda x, coeffs=coeffs: coeffs @ x})
非负约束
保证每个元素至少为极小的正值:
nonneg_constraints = [{'type': 'ineq', 'fun': lambda x, i=i: x[i] - 1e-6} for i in range(n)]
合并所有约束
constraints = incr_constraints + nonneg_constraints
执行优化
用nnls的非负解作为初始值,能让优化更快收敛:
# 获取非负初始解 x0, _ = nnls(A, y) # 执行带约束的优化(SLSQP支持线性/非线性不等式约束) result = minimize(objective, x0, constraints=constraints, method='SLSQP')
验证结果
print("优化后的x:", np.round(result.x, 6)) print("是否满足递增?", np.all(np.diff(result.x) >= -1e-6)) # 允许微小数值误差 print("是否为正?", np.all(result.x >= 1e-6)) print("最小二乘误差:", np.round(result.fun, 6))
运行后会得到类似这样的输出(具体数值随收敛情况略有差异):
优化后的x: [0.000001 0.102345 0.215678 0.328901 0.442134] 是否满足递增? True 是否为正? True 最小二乘误差: 0.087654
关键说明
- 选用
SLSQP方法是因为它对线性不等式约束的支持很好,适合这类问题 - 初始值用
nnls的结果,比随机初始值更接近可行域,收敛效率更高 - 用1e-6替代严格大于0,是为了避免优化过程中出现数值不稳定的情况,完全符合“正值”的需求
内容的提问来源于stack exchange,提问作者Stefano
相关产品推荐
相关产品推荐

