矩阵目标函数优化遇NaN问题:求配置方案或替代算法
问题描述
我有资产A和B的权重矩阵与收益矩阵:
weights = np.array([[.6, .4], [.5, .5], [.4, .6]]) # 所有元素满足 0 < w < 1 returns = np.array([[1.25, 2.5], [0.64, 0.5], [1.5, 1.6]]).T
希望找到新的权重矩阵,优化如下目标函数:计算weights与returns乘积矩阵的对角线元素乘积并减1,定义如下:
def objective_function(weights, returns): mat = np.product(np.diag(weights @ returns)) - 1 return mat # 示例输出:0.5561
尝试将权重矩阵扁平化后用Scipy的minimize方法优化,但得到全NaN的权重矩阵:
import numpy as np from scipy.optimize import minimize # 重塑为接受3x2矩阵的函数 def funct(weights_flat): weights = weights_flat.reshape((3, 2)) mat = -(np.product(np.diag(weights @ returns)) - 1) return mat # 约束条件:每列元素和为1 constraints = ({'type': 'eq', 'fun': lambda w: np.sum(w, axis=0) - 1}) # 初始猜测(一维数组) initial_guess_flat = np.ones(6) # 执行优化 result = minimize(funct, initial_guess_flat, method='SLSQP', constraints=constraints) # 获取优化后的权重 optimized_weights = result.x.reshape((3, 2)) print("Optimized Weights:") print(optimized_weights)
运行结果:
>>> Optimized Weights: [[nan nan] [nan nan] [nan nan]]
需解决如何重新配置优化函数实现预期效果,或推荐适用的优化包/算法。
解决方案
问题根源
- 初始猜测不合理:初始值用
np.ones(6),重塑后每列和为3,远偏离约束要求的1,易引发数值不稳定。 - 缺少边界约束:原问题要求权重
0 < w < 1,但未添加该约束,优化中可能出现负数或超过1的值,导致计算异常。 - 约束定义错误:一维输入数组直接用
np.sum(w, axis=0)会报错,需先重塑为矩阵再计算列和。
修正后的代码
import numpy as np from scipy.optimize import minimize # 固定收益矩阵 returns = np.array([[1.25, 2.5], [0.64, 0.5], [1.5, 1.6]]).T # 目标函数(最大化原目标,返回负值供minimize最小化) def funct(weights_flat): weights = weights_flat.reshape((3, 2)) diag_elements = np.diag(weights @ returns) obj_value = np.product(diag_elements) - 1 return -obj_value # 约束:每列元素和为1 def column_sum_constraint(w): weights = w.reshape((3, 2)) return np.sum(weights, axis=0) - np.ones(2) # 变量边界:每个权重在(0,1)之间,用微小偏移避免0/1导致梯度问题 bounds = [(1e-6, 1-1e-6)] * 6 # 合理初始猜测:每列均匀分布,满足列和为1的近似条件 initial_guess = np.tile(np.array([1/3, 1/3, 1/3]), 2) # 执行优化 constraints = {'type': 'eq', 'fun': column_sum_constraint} result = minimize(funct, initial_guess, method='SLSQP', constraints=constraints, bounds=bounds) # 输出结果 if result.success: optimized_weights = result.x.reshape((3, 2)) print("优化后的权重矩阵:") print(optimized_weights) final_obj = -result.fun print(f"最终目标函数值:{final_obj:.4f}") else: print("优化失败,原因:", result.message)
关键修正说明
- 初始猜测:改为每列元素均匀分布,让优化器从接近约束的状态开始迭代,提升收敛性。
- 边界约束:添加
bounds限制权重范围,避免非法值导致计算NaN。 - 约束函数修复:先重塑数组为矩阵,再计算列和,确保约束逻辑正确。
- 数值稳定性:用
1e-6替代0和1,防止梯度计算出现奇异值。
替代方案推荐
trust-constr方法:Scipy中更适合约束优化的方法,对非线性约束和边界的支持更稳健。- Pyomo/CVXPY:专业优化建模语言,适合构建复杂优化模型,代码可读性更强。
内容的提问来源于stack exchange,提问作者python_beginner
相关产品推荐
相关产品推荐

