Scipy.optimize向量约束优化维度不匹配报错排查
问题根因
报错来自三处配置错误,直接触发维度不匹配和逻辑失效:
bounds参数长度必须和优化变量w的维度完全匹配:你的权重向量是10维(对应10个资产),但拼接后的bnds包含1个冗余b1、10个权重边界、1个波动率边界,总共12组边界,和变量维度不匹配,触发np.clip广播错误。constraints参数要求传入字典组成的一维列表,你当前定义的cons嵌套了非负约束的子列表,结构不符合scipy接口规范。- 逻辑错误:
bounds仅用于给单个优化变量设置上下限,你要限制的组合波动率是所有权重的聚合函数,不是独立优化变量,不能写在bounds里;且你原来的波动率约束仅要求方差大于0,未生效传入的波动率上下限参数。
修正要点
- 删掉冗余的b1、b3边界配置,仅给10个权重变量设置非负边界即可。
- 将
cons展平为一维字典列表,补全波动率上下限约束:scipy的ineq类型约束要求函数返回值≥0,因此波动率下限对应w @ varcov @ w.T - lb_vol,上限对应ub_vol - w @ varcov @ w.T。 - 循环生成非负约束时显式捕获循环变量
i,避免Python闭包特性导致所有约束仅作用于最后一个权重。 - 显式指定支持约束和边界的
SLSQP求解器,避免scipy默认选用无约束求解器导致结果错误。
修正后可运行代码
import numpy as np from scipy.optimize import minimize def main(): fake_x = np.random.random((60, 10)) results = solution(fake_x, 0.05, 0.1) print(results) def initial_weights(fund): index = np.asarray(fund) dim_index = index.shape[1] return np.array([1/dim_index]*dim_index) def objective(w, fund): varcov = np.cov(fund, rowvar=False) obj_fun = 0.5 * np.log(w @ varcov @ w.T) return obj_fun def solution(x, lb_vol, ub_vol): varcov = np.cov(x, rowvar=False) w0 = initial_weights(x) cons = [ {"type": "eq", "fun": lambda w: 1 - np.sum(w)}, *[{"type": "ineq", "fun": lambda w, i=i: w[i]} for i in range(x.shape[1])], {"type": "ineq", "fun": lambda w: w @ varcov @ w.T - lb_vol}, {"type": "ineq", "fun": lambda w: ub_vol - w @ varcov @ w.T} ] bnds = [(0, None) for _ in range(x.shape[1])] res = minimize(objective, w0, bounds=bnds, args=(x,), constraints=cons, method='SLSQP') return res if __name__ == "__main__": main()
补充优化
非负约束已经通过bnds实现,不需要重复写在constraints列表里,要简化代码可以直接删掉cons里的非负约束行,运行效果完全一致。
内容的提问来源于stack exchange,提问作者mbronzo
相关产品推荐
相关产品推荐

