如何用Python计算最小方差?Pyomo建模求解问题求助
问题分析与修复方案
核心问题
协方差矩阵索引不匹配
你定义的资产名称是a1到a59,但协方差矩阵Cov的行/列索引是默认的0-58(因df为59列),直接用资产名称索引会触发KeyError。Param规则函数参数错误
Pyomo的Param规则函数必须以model作为第一个参数,你的get_covariance参数顺序不符合要求,无法正确加载协方差值。目标函数语法冗余
双重嵌套生成器可以简化为单层循环,避免语法歧义。未使用的二进制变量
定义了model.v但未添加任何相关约束,属于冗余代码,要么删除要么补充约束(比如限制选中资产数量)。
修复后的代码
!pip install pyomo !wget -N -q "https://ampl.com/dl/open/ipopt/ipopt-linux64.zip" !unzip -o -q ipopt-linux64 !apt-get install -y -qq glpk-utils import pandas as pd import numpy as np from pyomo.environ import * from pyomo.opt import SolverFactory # 生成与协方差矩阵索引匹配的资产名称 assets = [str(i) for i in range(59)] # 对应df的0-58列索引 df = pd.DataFrame(np.random.randint(0,10,size=(36, 59))) Cov = df.cov() # 修正Param规则函数:第一个参数为model,后接索引i,j def get_covariance(model, i, j): return Cov.loc[int(i), int(j)] model = ConcreteModel() model.i = Set(initialize=assets) model.w = Var(model.i, within=NonNegativeReals) # 非负权重(无卖空) model.cov = Param(model.i, model.i, rule=get_covariance, doc='covariance') # 简化目标函数:最小化投资组合方差 model.objective = Objective(expr=sum(model.w[i] * model.w[j] * model.cov[i,j] for i in model.i for j in model.i), sense=minimize) # 权重和为1的约束 model.Const1 = Constraint(expr=sum(model.w[i] for i in model.i) == 1) # 调用IPOPT求解,打开tee=True查看求解过程 solver = SolverFactory('ipopt', executable='/content/ipopt') results = solver.solve(model, tee=True) # 输出求解结果 print("求解状态:", results.solver.status) print("最优目标值(最小方差):", model.objective()) print("最优权重(忽略极小值):") for i in model.i: if model.w[i].value > 1e-6: print(f"资产{i}: {model.w[i].value:.4f}")
额外说明
- 如果需要构建稀疏投资组合(限制选中资产数量),可补充以下约束(示例为最多选10个资产):
model.v = Var(model.i, domain=Binary) # 权重>0时必须选中对应资产 def invest_rule(model, i): return model.w[i] <= model.v[i] model.invest_constr = Constraint(model.i, rule=invest_rule) # 限制选中资产总数 model.asset_limit = Constraint(expr=sum(model.v[i] for i in model.i) <= 10) - 无卖空约束下的最小方差解,本质是将全部权重分配给单一方差最小的资产,求解器结果会与该解析解一致。
内容的提问来源于stack exchange,提问作者Reza
相关产品推荐
相关产品推荐

