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

为何修改scipy optimize的x0初始点会导致优化结果不理想?

为什么修改scipy optimize的初始点x0会得到次优结果?

问题描述

我用scipy optimize运行优化器,目标是找到一组数值,让它和给定列表回归时获得最高的R-Squared值。但发现修改x0初始点会得到次优结果:

  • 正常运行时x0设为x0=np.random.uniform(0.01, 50, len(returns)),能得到最优解
  • 改成x0=np.random.uniform(0.01, 500, len(returns))(数值仍在bounds范围内)时,输出就不是最优解了
  • 原本想把x0设为startvalues但没成功,进而发现这个问题
  • 试过移除斜率约束后情况改善,但这不符合需求,期望两种x0设置能得到相似结果,想问是不是忽略了scipy optimize的基础原理,还有没有其他优化库可用?

完整代码如下:

import pandas as pd
import numpy as np
from scipy import stats
from scipy.optimize import minimize, LinearConstraint

returns = {'Returns': [0.060458679, 0.061902247, 0.066269106, 0.080471895, 0.10595085, 0.086491221, 0.113036617, 0.137770782, 0.0777593, 0.070083323, 0.072254624]}
startvalues = {'Value': [14214252.35, 1401493.11, 14877567.11, 30553699.53, 11417231.53, 3698585.80, 4449329.62, 7111866.99, 4714928.31, 7196446.00, 22750284.22]}

returns = pd.DataFrame(returns)
startvalues = pd.DataFrame(startvalues)

def objective_function(values):
    returns['Risk Not Optimal'] = values
    returns['Log Risk Not Optimal'] = np.log(returns['Risk Not Optimal'])
    _, _, r_value, _, _ = stats.linregress(returns['Returns'], returns['Log Risk Not Optimal'])
    r_squared = r_value ** 2
    return -r_squared

def slope_constraint(values):
    returns['Risk Not Optimal'] = values
    slope, _, _, _, _ = stats.linregress(returns['Returns'], np.log(returns['Risk Not Optimal']))
    return slope - 14

# Define the bounds for the values of 'Risk Not Optimal'
bounds = [(0.01, 100000000)] * len(returns)  # Use the length of the DataFrame

# Define the slope constraint
slope_cons = {'type': 'eq', 'fun': slope_constraint}

# Perform optimization to maximize the negative R-squared
result = minimize(objective_function, x0=np.random.uniform(0.01, 50, len(returns)), constraints=slope_cons, bounds=bounds)

best_list = result.x
best_r_squared = -result.fun  # Convert back to positive

print("Best List:", best_list)
print("Best R-squared:", best_r_squared)

问题根源

1. 目标函数是非凸的

你的目标是最大化R²,但R²基于线性回归结果计算,整个目标函数的曲面不是凸的——存在多个局部最优解。scipy默认的优化算法(如L-BFGS-B)是局部优化算法,它只会从初始点出发,收敛到附近的局部最优,而非全局最优。当初始点落在不同的局部最优区域时,结果自然不同。

2. 斜率约束压缩了可行域

你的slope_constraint要求回归斜率严格等于14,这个等式约束把可行域限制得极窄,局部最优解的分布会更零散。初始点稍微偏离全局最优区域,算法就容易卡在其他满足约束的局部最优里。

3. 初始点范围扩大的影响

当初始点从0.01-50扩大到0.01-500时,初始点落在全局最优区域外的概率大幅提升,算法直接收敛到附近的局部最优,自然得不到和之前一致的结果。


解决办法

1. 多初始点随机搜索

既然局部优化依赖初始点,就用多组不同初始点跑优化,在结果里选R²最高的:

best_r_squared = -np.inf
best_list = None

# 跑20次不同初始点,次数可按需调整
for _ in range(20):
    x0 = np.random.uniform(0.01, 500, len(returns))
    result = minimize(objective_function, x0=x0, constraints=slope_cons, bounds=bounds)
    current_r2 = -result.fun
    if current_r2 > best_r_squared:
        best_r_squared = current_r2
        best_list = result.x

print("最优结果:", best_list)
print("最高R-squared:", best_r_squared)

2. 改用全局优化算法

scipy自带全局优化工具differential_evolution,无需依赖初始点,能在整个可行域搜索全局最优:

from scipy.optimize import differential_evolution

# differential_evolution直接接收要最小化的目标函数(即-R²)
result = differential_evolution(objective_function, bounds=bounds, constraints=slope_cons)
best_list = result.x
best_r_squared = -result.fun

3. 修复x0=startvalues的问题

之前用startvalues失败是因为它是DataFrame,需要转成numpy数组:

x0 = startvalues['Value'].values  # 提取数组作为初始点

替代优化库

如果scipy的工具不够用,可以试试这些:

  • Optuna:基于贝叶斯优化的框架,适合黑箱优化,能自动调整搜索策略
  • Pyomo:面向数学规划的建模库,支持多种求解器(包括全局求解器)
  • Nevergrad:Facebook开源的无梯度优化库,适配复杂非凸优化问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:57:13