如何在scipy.optimize.nnls中固定部分系数求解剩余非负最小二乘解?
如何在scipy.optimize.nnls中固定部分系数值?
好问题!scipy.optimize.nnls本身并没有直接提供固定部分系数的参数,但我们可以通过重构优化问题的方式轻松实现这个需求。核心思路是把固定系数的影响从目标方程中提前剔除,然后对剩余的自由变量求解非负最小二乘。
具体原理
原问题是求解:
min ||A @ x - b||²,约束x ≥ 0
如果我们要固定x[i] = fixed_val(fixed_val ≥ 0,符合非负约束),可以把这一项从方程中分离出来:
- 计算固定项对目标向量的贡献:
A[:, i] * fixed_val - 用原目标向量减去这个贡献,得到新的目标向量:
b_new = b - A[:, i] * fixed_val - 从矩阵
A中删除第i列,得到新的矩阵A_new - 对
A_new和b_new运行nnls,得到剩余自由变量的解x_rest - 把固定值插回
x_rest的对应位置,得到最终的完整解x
基于你的代码修改的示例
假设你要固定第一个系数为0.9,可以这样修改代码:
#! /usr/bin/env python3 import numpy as np import scipy.optimize as soptimize if __name__ == '__main__': C = np.array([[112.771820, 174.429720, 312.175750, 97.348620], [112.857010, 174.208300, 312.185270, 93.467580], [114.897210, 175.661850, 314.275100, 99.015480] ]); d = np.array([[112.7718, 174.4297, 312.1758, 97.3486]]); # 配置固定参数:索引0对应的值为0.9 fixed_idx = 0 fixed_val = 0.9 for line in d: # 1. 重构矩阵:移除固定系数对应的列 A_new = np.delete(C.T, fixed_idx, axis=1) # 2. 重构目标向量:减去固定项的贡献 b_new = line - C.T[:, fixed_idx] * fixed_val # 3. 求解剩余变量的非负最小二乘 ret_rest, _ = soptimize.nnls(A_new, b_new) # 4. 插入固定值,得到完整解 ret = np.insert(ret_rest, fixed_idx, fixed_val) print("带固定值的解:", ret) # 可选:验证拟合误差 print("拟合误差平方:", np.linalg.norm(C.T @ ret - line)**2)
扩展:固定多个系数的情况
如果需要固定多个系数,只需要批量处理即可。比如固定索引0和1的值为0.9和0.06:
# 配置多个固定参数 fixed_indices = [0, 1] fixed_vals = [0.9, 0.06] for line in d: # 计算所有固定项的总贡献 total_fixed_contrib = sum(C.T[:, idx] * val for idx, val in zip(fixed_indices, fixed_vals)) b_new = line - total_fixed_contrib # 删除所有固定列 A_new = np.delete(C.T, fixed_indices, axis=1) # 求解剩余变量 ret_rest, _ = soptimize.nnls(A_new, b_new) # 组装完整解 ret = np.zeros(C.T.shape[1]) ret[fixed_indices] = fixed_vals # 填充剩余自由变量的解 free_indices = np.setdiff1d(range(C.T.shape[1]), fixed_indices) ret[free_indices] = ret_rest print("多固定值的解:", ret)
注意事项
- 固定值必须非负,否则违反nnls的非负约束,结果没有实际意义。
- 如果重构后的
b_new出现负数,nnls仍然会求解,但建议检查最终解的拟合效果是否符合预期。 - 这种方法完全基于原生的
nnls函数,不需要引入额外的优化库,效率和原函数一致。
内容的提问来源于stack exchange,提问作者elody wenge
相关产品推荐
相关产品推荐

