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

Sklearn分类模型Pickle序列化后结果不一致问题求助

解决Sklearn模型序列化后评估结果不一致的问题

首先看你的代码,发现一个关键bug:第二个绘制ROC曲线的回调RocPlot没有把model下拉框的选中值作为输入参数,导致回调里的mod变量要么未定义,要么使用的是全局的旧值,这会让你加载错误的模型,自然评估结果和原模型完全不符!这大概率是AUC差异巨大的直接原因。

先修正这个回调的参数问题,然后我们再解决序列化和模型保存的其他潜在问题:

1. 修复回调的参数传递问题

修改RocPlot回调,把Input('model', 'value')加入输入列表,确保加载的模型和用户选择的一致:

@app.callback(
    Output('my-graph', 'figure'),
    [Input('roc','n_clicks'), Input('model', 'value')]  # 新增model输入参数
)
def RocPlot(button, mod):  # 新增mod参数接收下拉框值
    if button is None:
        return {}  # Dash的figure需要字典格式,原代码返回的[{}]会报错
    else:
        ### loading models
        if mod == 'logreg':
            with open("python_logreg_model.pkl", "rb") as file_handler:
                model = pickle.load(file_handler)
        elif mod == 'mlp':
            with open("python_mlp_model.pkl", "rb") as file_handler:
                model = pickle.load(file_handler)
        # 其他模型的加载逻辑...
        
        # 后续ROC绘制代码不变
        fp, tp, threshold= metrics.roc_curve(y_test, model.predict_proba(x_test)[:,1])
        AUC= metrics.auc(fp, tp)
        lw = 2
        trace1 = go.Scatter(x=fp, y=tp, mode='lines', line=dict(color='darkorange', width=lw), name='ROC curve (area = %0.2f)' % AUC )
        trace2 = go.Scatter(x=[0, 1], y=[0, 1], mode='lines', line=dict(color='navy', width=lw, dash='dash'), showlegend=False)
        layout = go.Layout(title='Receiver operating characteristic example', xaxis=dict(title='False Positive Rate'), yaxis=dict(title='True Positive Rate'))
        print('plot done')
        return{
            'data': [trace1, trace2],
            'layout': layout
        }

2. 固定模型的随机状态

Sklearn的很多模型(比如MLPClassifier、部分solver下的LogisticRegression)包含随机初始化过程,如果不固定random_state,每次训练的模型参数会有差异,导致评估结果波动。训练模型时一定要指定这个参数:

# 训练LogisticRegression时
logreg = LogisticRegression(random_state=42)
# 训练MLPClassifier时
mlp = MLPClassifier(random_state=42)

3. 使用Joblib替代Pickle(Sklearn官方推荐)

对于Sklearn模型,官方更推荐用joblib来序列化,因为它对NumPy数组和稀疏矩阵的处理更高效,能避免一些pickle可能出现的序列化异常:

# 保存模型
from joblib import dump, load
dump(logreg, "python_logreg_model.joblib")

# 加载模型
model = load("python_logreg_model.joblib")

4. 保存完整的预处理Pipeline(如果有数据预处理步骤)

如果你的数据集在训练前做了标准化、编码等预处理(比如StandardScaler、OneHotEncoder),只保存模型会导致加载后用不同的预处理参数处理测试集,结果完全错误。应该把预处理步骤和模型打包成Pipeline,然后保存整个Pipeline:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

# 构建包含预处理的Pipeline
pipe = Pipeline([
    ('scaler', StandardScaler()),  # 预处理步骤
    ('logreg', LogisticRegression(random_state=42))  # 模型
])
pipe.fit(x_train, y_train)

# 保存Pipeline
dump(pipe, "logreg_pipeline.joblib")

# 加载后直接使用,无需单独处理预处理
loaded_pipe = load("logreg_pipeline.joblib")
fp, tp, threshold = metrics.roc_curve(y_test, loaded_pipe.predict_proba(x_test)[:,1])

5. 确保训练和评估用的数据集一致

检查x_train、y_train、x_test、y_test在两个回调中是否是完全相同的数据集,避免在回调之间不小心修改了数据集(比如重新划分了训练测试集)。可以把数据集的划分放在回调外部,确保全局唯一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:04:32