
在模型训练与部署分离的场景下,若每次预测都新建ordinalencoder实例,会导致所有类别被错误编码为0;正确做法是复用训练阶段拟合好的编码器。
在模型训练与部署分离的场景下,若每次预测都新建ordinalencoder实例,会导致所有类别被错误编码为0;正确做法是复用训练阶段拟合好的编码器。
问题根源在于:你在训练脚本中使用 enc.fit_transform(...) 正确拟合了编码器,但未保存该拟合后的编码器对象;而在 Streamlit 应用中,每次点击“Predict”按钮时,都重新初始化了一个全新的 OrdinalEncoder() 实例,并仅对其传入单条(或少量)含空字符串/缺失值的样本调用 fit_transform。由于 OrdinalEncoder 对单一值(尤其是空字符串 "")拟合时,会将其映射为 0,且无其他类别可供区分,因此所有分类列最终都被编码为 0 —— 这正是你观察到“始终显示相同值”的根本原因。
✅ 正确做法是:将训练阶段拟合好的 OrdinalEncoder 与模型一同持久化保存,并在推理时复用它。
✅ 修改建议(训练端)
在训练脚本末尾,除保存模型外,还需保存已拟合的编码器:
# ... 训练流程保持不变 ...
enc = OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1) # 推荐:处理未见类别
X_enc = enc.fit_transform(df_copied[cat_cols])
df_copied[cat_cols] = pd.DataFrame(X_enc, columns=cat_cols)
# ... 后续训练、SMOTE、建模等 ...
# 保存模型和编码器
import pickle
with open('dtc_model.pkl', 'wb') as f:
pickle.dump(dtc, f)
with open('ordinal_encoder.pkl', 'wb') as f:
pickle.dump(enc, f) # 关键:保存已拟合的 encoder!
⚠️ 注意:建议设置 handle_unknown='use_encoded_value' 和 unknown_value=-1,以增强对部署时新类别(如用户误选空值)的鲁棒性。
✅ 修改建议(Streamlit 端)
加载模型的同时,也加载并复用训练时保存的编码器:
with open('dtc_model.pkl', 'rb') as f:
model = pickle.load(f)
with open('ordinal_encoder.pkl', 'rb') as f:
enc = pickle.load(f) # 关键:复用训练好的 encoder!
# ... 输入收集逻辑不变 ...
if st.button("Predict"):
data = {
'age': int(age), 'bp': float(bp), 'sg': sg, 'al': al, 'su': su,
'rbc': rbc, 'pc': pc, 'pcc': pcc, 'ba': ba, 'bgr': float(bgr),
'bu': float(bu), 'sc': float(sc), 'sod': float(sod), 'pot': float(pot),
'hemo': float(hemo), 'pcv': float(pcv), 'wc': float(wc), 'rc': float(rc),
'htn': htn, 'dm': dm, 'cad': cad, 'appet': appet, 'pe': pe, 'ane': ane
}
df_input = pd.DataFrame([data], columns=cols)
# 仅对 categorical 列进行 transform(非 fit_transform!)
cat_cols = [col for col in df_input.columns if df_input[col].dtype == 'object']
df_encoded = df_input.copy()
df_encoded[cat_cols] = enc.transform(df_encoded[cat_cols]) # ← 注意:是 transform,不是 fit_transform
prediction = model.predict(df_encoded)[0]
st.write("Positive" if prediction == 1 else "Negative")
? 补充说明与注意事项
- fit_transform vs transform:训练时用 fit_transform 学习映射关系;预测时必须用 transform 应用该关系。重复调用 fit_transform 会重置编码逻辑。
- 空值/缺失值处理:原始数据中 "", "normal", "abnormal" 等字符串若含空字符串(""),需在训练前统一处理(如替换为 np.nan 并用 mode 填充),否则 OrdinalEncoder 会将其视为有效类别,影响泛化能力。
- 列顺序一致性:确保 Streamlit 输入 DataFrame 的列名顺序与训练时完全一致(你已显式指定 columns=cols,这点做得很好)。
- 类型安全:st.text_input 返回字符串,务必显式转换为 int/float;对分类字段(如 rbc, pc)应避免传入空字符串参与编码——可在前端加校验,或在编码前做清洗(如 df_input[cat_cols] = df_input[cat_cols].replace("", np.nan).fillna("unknown"))。
遵循以上修改后,编码结果将准确反映训练阶段学习到的类别序数关系,模型预测也将恢复应有的判别能力。











