我正在使用 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)
但是,当我尝试获取 Shap 图时,出现以下错误:
shap.summary_plot(shap_values, X_test_processed)
- 错误:类型错误:只有整数标量数组可以转换为标量索引
shap.summary_plot(shap_values,X_test_processed,plot_type =“bar”)
- 错误:类型错误:只有整数标量数组可以转换为标量索引
shap.plots.beeswarm(shap_values)
- 错误:ValueError:蜂群图不支持对具有多个维度的实例进行绘图解释!
shap.plots.bar(shap_values)
- 错误:IndexError:列表索引超出范围
我做错了什么?请让我知道解决此问题的任何想法。
最佳答案
之后,shap_values
的形状为 (328, 7, 2)
,并且 beeswarm 错误消息最有用:所有内容都只是一个二维数组。由于某种原因,你得到了两个类的解释,而不仅仅是正类的解释(负类的解释正好与那些类相反);将 [:, :, 1]
放在 shap_values
后面,然后就会为我显示绘图。
我已经在 Colab 上对此进行了测试,但这并不容易允许 python 3.8,因此也不允许 sklearn 1.1,因此我必须进行一些修改。如果它不适合您,请告诉我,我将在本地构建一个更紧密的环境。
如果能理解为什么 shap 会为你提供这两个类的解释,那就太好了。我确实注意到 y
具有分类 pandas 类型,但转换为 int 不会改变任何内容。
关于scikit-learn - 使用 sklearn pipeline 进行分类任务时,形状图(树解释器)中出现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73605032/