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

为何scipy minimize得到的最优系数始终与初始猜测值相同?

问题排查:scipy.minimize优化结果始终等于初始猜测值

我有一个输出为0或1的分类模型,目标是最小化预测值与观测值的绝对误差总和。mod_7是未经过特定列过滤的初始数据集,但发现无论修改first_guess的值,best_fit的结果始终和初始猜测一致,求排查原因。

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

np.random.seed(0)
mod_7 = pd.DataFrame(np.random.randint(2,size=(100, 5)), columns=['IsCar', 'Is10places', 'observed_value','hybrid_score', 'col_score'])


def fuel_efficiency_grade_calculator(df):
    df['total_score_adj'] = np.where(df['hybrid_score'] == 1, df['total_score'] + 1 , df['total_score'] - 1)
    return df


def func(params):
    app_coef, ext_coef = params

    df_temp = mod_7[(mod_7['IsCar'] != 1) & (mod_7['Is10places'] == 1)]
    df_temp['total_score'] = 0.55 + app_coef * df_temp["hybrid_score"] + ext_coef * df_temp["col_score"]

    # compute grades
    df_temp = fuel_efficiency_grade_calculator(df_temp)  # this function does some data transfromation, but the final goal is compute column df_temp['fuel_efficient']
    df_temp['predicted_value'] = np.where(df_temp['total_score_adj'] >= 7, 1, 0)

    return abs(sum(df_temp['predicted_value'] - df_temp['observed_value']))


# choose reasonable values for your 7 parameters here,
# i.e. close to the "right" answer, this may take a few tries
first_guess = [3, 5]

# here we run the minimisation
res = minimize(func, first_guess)

# this is an array of your best fit values for a1-a7
best_fit = res.x

核心问题分析

你的目标函数func是非连续、非光滑的,这直接导致scipy.minimize默认的梯度类优化算法完全失效:

  • 预测值predicted_value是阶跃函数,只有当total_score_adj跨越7这个阈值时,调整系数才会改变预测结果;如果初始猜测对应的total_score_adj大部分都离7很远,调整系数无法让更多样本跨越阈值,误差总和就不会变化,算法会误以为当前点已经是最优解。
  • 梯度类算法依赖目标函数的导数来寻找下降方向,但阶跃函数的导数在大部分点都是0,算法找不到优化方向,只能停在初始点。

另外还有两个细节问题:

  • 直接在切片后的df_temp上新增列会触发pandas的SettingWithCopyWarning,建议用.copy()创建独立副本:df_temp = mod_7[(mod_7['IsCar'] !=1) & (mod_7['Is10places'] ==1)].copy()
  • 注释提到要优化7个参数,但代码里只处理了2个,不过这不是当前问题的核心。

解决建议

方案1:替换为光滑损失函数

把绝对误差总和换成可导的近似损失,比如逻辑回归的交叉熵损失,让算法能通过梯度找到优化方向:

def func(params):
    app_coef, ext_coef = params
    df_temp = mod_7[(mod_7['IsCar'] !=1) & (mod_7['Is10places'] ==1)].copy()
    df_temp['total_score'] = 0.55 + app_coef * df_temp["hybrid_score"] + ext_coef * df_temp["col_score"]
    df_temp['total_score_adj'] = np.where(df_temp['hybrid_score'] ==1, df_temp['total_score']+1, df_temp['total_score']-1)
    # 用sigmoid将得分映射为0-1概率,计算交叉熵损失(加1e-8避免log(0)报错)
    prob = 1/(1+np.exp(-(df_temp['total_score_adj'] -7)))
    loss = -np.sum(df_temp['observed_value']*np.log(prob+1e-8) + (1-df_temp['observed_value'])*np.log(1-prob+1e-8))
    return loss

方案2:使用非梯度优化算法

给minimize指定支持非光滑函数的算法,比如Nelder-Mead单纯形法,它不需要计算梯度:

res = minimize(func, first_guess, method='Nelder-Mead', options={'maxiter': 10000, 'fatol': 1e-4})

注:该算法收敛速度较慢,可能需要调整options里的迭代次数、精度参数来优化效果。

方案3:调整决策边界或特征范围

检查当前total_score_adj的分布,如果所有样本的得分都远低于或远高于7,说明这个阈值设置不合理。可以降低阈值,或者对特征进行缩放,让系数调整能影响更多样本的预测结果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 00:35:17