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

使用Sklearn Pipeline做分类任务时Shap树解释器绘图报错求助

问题描述

使用Sklearn Pipeline完成泰坦尼克号分类任务后,调用SHAP可视化时出现多种错误,代码及报错如下:

完整代码

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OrdinalEncoder

import shap


# -----------------------------------------------------------------------------
# Data
# -----------------------------------------------------------------------------

X, y = fetch_openml("titanic", version=1, as_frame=True, return_X_y=True)

categorical_columns = ["pclass", "sex", "embarked"]
numerical_columns = ["age", "sibsp", "parch", "fare"]

X = X[categorical_columns + numerical_columns]   # [1309, 7] , there is Nan values.
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)


# -----------------------------------------------------------------------------
# Data preprocessing
# -----------------------------------------------------------------------------


categorical_encoder = OrdinalEncoder(
    handle_unknown="use_encoded_value", unknown_value=-1, encoded_missing_value=-1
)

numerical_imputer = SimpleImputer(strategy="mean")


preprocessing = ColumnTransformer(
    [
        ("cat", categorical_encoder, categorical_columns),   
        ("num", numerical_imputer, numerical_columns),
    ],
    verbose_feature_names_out=False,   
)


# -----------------------------------------------------------------------------
# Pipeline
# -----------------------------------------------------------------------------

rf = Pipeline(
    [
        ("preprocess", preprocessing),
        ("classifier", RandomForestClassifier(random_state=42)),
    ]
)


rf.fit(X_train, y_train)


print(f"RF train accuracy: {rf.score(X_train, y_train):.3f}")
print(f"RF test accuracy: {rf.score(X_test, y_test):.3f}")


# -----------------------------------------------------------------------------
# Shap
# -----------------------------------------------------------------------------

explainer = shap.Explainer(rf["classifier"], feature_names=rf["preprocess"].get_feature_names_out())

X_test_processed = rf['preprocess'].transform(X_test)

shap_values = explainer(X_test_processed)

报错情况

  • 执行shap.summary_plot(shap_values, X_test_processed):TypeError: 仅整数标量数组可转换为标量索引
  • 执行shap.summary_plot(shap_values, X_test_processed, plot_type="bar"):TypeError: 仅整数标量数组可转换为标量索引
  • 执行shap.plots.beeswarm(shap_values):ValueError: 蜂群图不支持绘制具有多维实例的解释结果!
  • 执行shap.plots.bar(shap_values):IndexError: 列表索引超出范围

解决思路

核心问题原因

RandomForestClassifier即使是二分类任务,默认也会输出每个类别的概率,属于多输出模型。因此explainer(X_test_processed)返回的SHAP值是三维数组(样本数 × 特征数 × 类别数),而多数SHAP可视化函数仅支持处理单输出(二维数组)的情况,这是所有报错的根源。

具体修复步骤

  1. 提取单类别SHAP值
    二分类任务中通常关注正类(比如泰坦尼克号任务的“存活”类)的SHAP值,只需从三维数组中提取对应类别的维度:

    # 先查看类别顺序,确认正类索引
    print(rf["classifier"].classes_)
    # 假设正类是索引1的类别,提取对应SHAP值
    shap_values = shap_values[..., 1]
    
  2. 修改SHAP代码块
    更新后的SHAP部分代码如下:

    # -----------------------------------------------------------------------------
    # Shap
    # -----------------------------------------------------------------------------
    
    explainer = shap.Explainer(rf["classifier"], feature_names=rf["preprocess"].get_feature_names_out())
    
    X_test_processed = rf['preprocess'].transform(X_test)
    
    shap_values = explainer(X_test_processed)
    # 提取正类SHAP值,适配可视化要求
    shap_values = shap_values[..., 1]
    
  3. 重新运行可视化函数
    现在以下代码均可正常执行:

    • 摘要散点图:
      shap.summary_plot(shap_values, X_test, feature_names=rf["preprocess"].get_feature_names_out())
      
    • 特征重要性条形图:
      shap.summary_plot(shap_values, X_test, plot_type="bar", feature_names=rf["preprocess"].get_feature_names_out())
      
    • 蜂群图:
      shap.plots.beeswarm(shap_values)
      
    • 特征重要性条形图(另一种接口):
      shap.plots.bar(shap_values)
      

额外优化建议

  • 传入原始测试集X_test而非预处理后的X_test_processed,可视化时会显示原始特征取值(如性别显示male/female,而非编码后的0/1),可读性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:09:17