使用 sklearn pipeline 进行分类任务时,形状图(树解释器)中出现错误

Moh*_*mad 3 pipeline classification treemodel scikit-learn shap

我正在使用 sklearn 管道进行分类任务,如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

然而,当我尝试获取 Shap 图时,出现以下错误:

shap.summary_plot(shap_values, X_test_processed)

  • 错误:TypeError:只有整数标量数组可以转换为标量索引

shap.summary_plot(shap_values, X_test_processed, plot_type="bar")

  • 错误:类型错误:只有整数标量数组可以转换为标量索引

shap.plots.beeswarm(shap_values)

  • 错误:ValueError:蜂群图不支持对具有多个维度的实例进行绘图解释!

shap.plots.bar(shap_values)

  • 错误:IndexError:列表索引超出范围

我究竟做错了什么?请让我知道解决这个问题的任何想法。

Ben*_*ger 5

之后,shap_values有 shape (328, 7, 2),并且 beeswarm 错误消息是最有用的:一切都只期望一个二维数组。由于某种原因,你得到了两个类的解释,而不仅仅是正类的解释(负类的解释正好与那些类相反);把所有地方都放在[:, :, 1]后面shap_values,情节就会为我显示。

我已经在 Colab 上对此进行了测试,但这并不容易允许 python 3.8,因此也不允许 sklearn 1.1,所以我必须进行一些修改。如果它不适合您,请告诉我,我将在本地构建一个更紧密的环境。

理解为什么shap 为您提供这两个类的解释仍然是件好事。我确实注意到它y有明确的 pandas 类型,但转换为 int 不会改变任何东西。

  • 谢谢。我使用 [:,:,1] 获得了 Shap 图。但是,它似乎只显示了一个类的 Shap 图。我记得 Shap 图使用不同的颜色显示分类任务中图上的所有类。(/sf/ask/5022739991/​​alues-for-each-class-on-a-multiclass-classification-problem-in)。 (2认同)