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

如何用Python生成与目标列表回归后R-squared最高的数值列表?

问题分析与解决方案

问题描述

给定一组数值列表,希望生成另一组数值,对其取自然对数后与原列表做线性回归能得到最高的R²。现有代码运行结果不符合预期,具体如下:

  • 预期的最优列表(存在多种可能解):
    Best List = [0.258288996, 0.29055507, 0.15215332, 0.395691366, 0.106867761, 0.096624222, 0.114833083, 0.239799601]
    
  • 实际运行结果:
    Best List: [1.         1.         1.         0.99999991 0.99999991 0.99999991  1.         1.        ]
    

原代码如下:

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

def objective_function(values, df):
    df['Risk Not Optimal'] = values
    df['Log Risk Not Optimal'] = np.log(df['Risk Not Optimal'])
    slope, intercept, r_value, p_value, std_err = stats.linregress(df['Returns'], df['Log Risk Not Optimal'])
    r_squared = r_value ** 2
    return -r_squared

data = [0.147490447, 0.15589857, 0.109691117, 0.177958696, 0.084455669, 0.077258315, 0.089590471, 0.142185032]
df = pd.DataFrame(data, columns=['Returns'])

# Define the bounds for the values of 'Risk Not Optimal'
bounds = [(0, 1)] * len(df)  # Use the length of the DataFrame

# Define the linear constraint for the length
constraint = LinearConstraint(np.ones(len(df)), lb=len(df), ub=len(df))

# Perform optimization to maximize the negative R-squared
result = minimize(objective_function, x0=[1] * len(df), args=(df,), bounds=bounds, constraints=constraint)

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. 核心错误分析

  • 约束条件完全错误:你设置的LinearConstraint要求所有变量的和等于len(df)(即8),但每个变量上限是1,8个变量的最大总和就是8,所以优化器只能返回全1(或接近1)的结果,对数后的值全部为0,线性回归的R²趋近于0,完全偏离需求。
  • 目标函数非光滑性:stats.linregress计算的R²是一个非光滑函数,scipy.minimize默认的L-BFGS-B优化器对这类函数优化效果差,容易陷入局部最优。
  • DataFrame副作用:在目标函数中直接修改传入的df会产生不可控的副作用,干扰后续计算。

2. 修正后的代码

调整约束条件(若无需总和约束则直接移除,若有实际需求可按需添加),更换优化器,同时重构目标函数避免副作用:

import numpy as np
from scipy import stats
from scipy.optimize import minimize

def objective_function(values, returns):
    # 直接计算对数,避免修改外部数据结构
    log_vals = np.log(values)
    # 提取R²值并返回其负值(转为最小化问题)
    _, _, r_value, _, _ = stats.linregress(returns, log_vals)
    return -(r_value ** 2)

# 原始数据转为numpy数组
returns = np.array([0.147490447, 0.15589857, 0.109691117, 0.177958696, 
                    0.084455669, 0.077258315, 0.089590471, 0.142185032])

# 变量边界:设置极小值下限避免log(0)报错
bounds = [(1e-8, 1.0) for _ in range(len(returns))]

# 初始值设为随机小数值,避免陷入局部最优
x0 = np.random.uniform(0.1, 0.5, size=len(returns))

# 使用SLSQP优化器,适配非光滑目标与边界约束
result = minimize(objective_function, x0=x0, args=(returns,), 
                  bounds=bounds, method='SLSQP', options={'maxiter': 1000})

best_list = result.x
best_r_squared = -result.fun

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

3. 更合适的库推荐

  • scipy.optimize:调整优化器(如SLSQP、Nelder-Mead)和初始值后,完全满足需求,无需额外依赖。
  • pymoo:适合添加复杂约束或多目标优化场景,灵活性更高。
  • optuna:基于贝叶斯优化的框架,对非光滑、非凸目标函数的优化效率优于传统梯度方法,更容易找到全局最优。

关键补充

如果需要总和约束(比如总和为1),可添加以下代码并传入minimize的constraints参数:

from scipy.optimize import LinearConstraint
constraint = LinearConstraint(np.ones(len(returns)), lb=1.0, ub=1.0)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:49:55