You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Scipy最小均方误差优化无迭代、循环异常问题排查

投资组合Beta零目标优化代码问题定位

核心问题根因拆解

1. for循环执行次数不符合预期的原因

  • 你写的range(1,2)本身就只会执行1次:Python的range(start, end)是左闭右开区间,仅包含start值、不包含end值,所以range(1,2)只会取到i=1这1个值,本身就达不到你预期跑2次的效果。如果要遍历所有日期列,range范围应该设为range(1, numDates+1)。
  • 你看到的N次重复执行,根本不是外层for循环触发的:你在目标函数minSqError里写了print(a,b),scipy的minimize每次迭代试探参数时都会调用一次目标函数,每调用一次就触发一次打印,大量迭代打印让你误以为是外层循环在重复运行。

2. 求解器只返回初始值、不迭代的原因

这个问题是3处代码逻辑错误叠加导致的:

  • 权重约束函数完全失效
    你写的Weight_constraint逻辑是在循环里反复执行TotalWeight = PortWeight - x[i],每次循环都会覆盖上一次的计算结果,最终返回值是1 - x[-1](即1减去最后一个资产的权重),根本不是「所有权重之和等于1」的约束。正确的约束返回值应该是np.sum(x) - 1,代表权重和与1的差值为0。错误的约束会让求解器判定初始点已经满足可行条件,梯度计算异常直接终止迭代。
  • 目标函数传参逻辑错误,优化变量被完全固定
    scipyminimize的调用规则是:第一个传入的位置参数是待优化的自由度变量x,后面args里传的是全程固定不变的常量参数。
    你现在的写法是把初始权重tempBetas['Weight']既作为初始猜测值传入,又放在args里当固定参数传给目标函数;且目标函数计算加权Beta时,用的是args里传进来的固定初始权重,完全没用到求解器迭代更新的优化变量(也就是你定义的第一个形参df,全程没参与目标值计算)。相当于不管求解器怎么调整权重参数,你算出来的误差值永远是初始等权重对应的结果,求解器判定初始点梯度为0,自然不会迭代。
  • 未指定适配约束的求解器方法
    你没有给minimize指定method参数,默认调用的BFGS算法本身不支持等式/不等式约束,即使约束写对了也会出现求解异常。带约束的优化场景应该指定method='SLSQP'或trust-constr。

修正后可运行代码

import pandas as pd
import numpy as np
from scipy.optimize import minimize

# 基础配置
SolverTarget = 0
numDates = len(BetaResults.iloc[0,1:])
numEquities = len(BetaResults.iloc[:,0])
equalWeight = 1 / numEquities
allocationResult = []

# 目标函数:第一个参数固定为待优化的权重数组x,后面接固定常量
def minSqError(x, beta_arr, target):
    port_beta = np.sum(x * beta_arr)
    return (target - port_beta) ** 2

# 权重和为1的等式约束
def weight_sum_constraint(x):
    return np.sum(x) - 1
cons = {'type':'eq', 'fun': weight_sum_constraint}
# 可选:添加权重非负约束,不允许做空
bounds = tuple((0,1) for _ in range(numEquities))

# 外层循环遍历所有日期
for date_col_idx in range(1, numDates+1):
    current_beta = BetaResults.iloc[:, date_col_idx].values
    x0 = np.array([equalWeight]*numEquities) # 等权重作为初始猜测
    
    # 初始权重校验
    if not np.isclose(x0.sum(), 1):
        print(f"列索引{date_col_idx}初始权重和异常,当前值{x0.sum()}")
        break
    
    # 执行优化
    opt_result = minimize(
        minSqError,
        x0=x0,
        args=(current_beta, SolverTarget),
        constraints=cons,
        bounds=bounds,
        method='SLSQP'
    )
    
    # 存储结果
    allocationResult.append({
        'date': BetaResults.columns[date_col_idx],
        'opt_weights': opt_result.x,
        'min_port_beta': np.sum(opt_result.x * current_beta),
        'converge_success': opt_result.success
    })

额外说明

如果你的Beta值全为正(比如示例里的0.3、0.42这类值),在权重非负、和为1的约束下,加权Beta永远不可能等于0,求解器会自动把尽可能多的权重分配给Beta最小的资产,得到约束条件下的最小Beta值。

内容的提问来源于stack exchange,提问作者dabrows

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 17:57:26