使用OneVsRestClassifier做多标签分类时预测结果异常问题求解
问题根因分析
- 核心错误:错误手动循环训练覆盖模型。你使用的
OneVsRestClassifier本身就支持直接传入多标签格式的y(即3列标签矩阵),不需要手动循环每个标签单独训练。你在循环中每次都对同一个LR_pipeline执行fit操作,前两次训练的vitamin_A、vitamin_C模型被后续训练覆盖,最终pipeline仅保留了最后一个vitamin_D的训练结果。再加上你测得vitamin_D的准确率为1.0,大概率数据集中vitamin_D=1的样本占比极高,所以不管输入什么特征都会输出1,你循环三次预测调用的都是这个vitamin_D的模型,自然全输出[1]。
补充:你循环中计算的单标签准确率数值是对的,因为刚fit完当前标签就做了测试,但循环结束后没有保留所有标签的模型,属于训练逻辑错误。 - 预测逻辑错误:
OneVsRestClassifier训练完成后一次预测就能输出所有标签的结果,不需要循环每个标签调用预测。 - 细节隐患:手动传列表做预测容易出现特征顺序和训练时不匹配的问题,建议用DataFrame传参保证特征对齐。
修正后的完整代码
训练部分
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.pipeline import Pipeline from sklearn.multiclass import OneVsRestClassifier from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score # 数据集拆分 X = df[['gender', 'age', 'weight', 'height']] y = df[['vitamin_A', 'vitamin_C', 'vitamin_D']] # 加random_state固定随机种子,保证结果可复现 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True, random_state=42) # 直接训练多标签模型,不需要循环 # 加max_iter避免sag solver收敛报错 LR_pipeline = Pipeline([('clf', OneVsRestClassifier(LogisticRegression(solver='sag', max_iter=1000), n_jobs=-1))]) LR_pipeline.fit(X_train, y_train) # 计算单标签准确率 pred_test = LR_pipeline.predict(X_test) acc_classifier = [accuracy_score(y_test[label], pred_test[:,i]) for i, label in enumerate(y.columns)] df_acc = pd.DataFrame({'Label': y.columns, 'Accuracy': acc_classifier}) print(df_acc)
预测部分(实现预期输出格式)
# 传入你需要的测试特征:gender=0, age=55, weight=64, height=128 data_test = pd.DataFrame([[0, 55, 64, 128]], columns=['gender', 'age', 'weight', 'height']) # 同时获取分类结果和预测概率 pred_labels = LR_pipeline.predict(data_test)[0] pred_probs = LR_pipeline.predict_proba(data_test)[0] # 拼接成预期输出格式 res = {} for idx, label in enumerate(y.columns): res[label] = pred_labels[idx] res[f"{label}_prob"] = round(pred_probs[idx], 2) res_df = pd.DataFrame([res]) # 打印输出 print(res_df.to_string(index=False))
内容的提问来源于stack exchange,提问作者Tawan
相关产品推荐
相关产品推荐

