【问题标题】:How to plot misclassified samples in shap?如何在 shap 中绘制错误分类的样本?
【发布时间】:2020-10-09 15:42:40
【问题描述】:

我有一个基因数据集,得分在 0 到 1 之间导致疾病的可能性(得分为 1 的基因已知会导致疾病,而得分为 0.74 的基因可能会导致疾病)。我正在尝试建立一个机器学习模型来预测回归分类中新基因的疾病评分。

我想查看已知疾病基因但得分较低的基因(例如得分为 1 但我的模型得分低于 0.8 的基因)的形状决策图。我正在努力将这些基因组合在一起进行绘图。

我的数据如下:

X:
Index   Feature1  Feature2   ... FeatureN
Gene1     1           0.2          10
Gene2     1           0.1          7
Gene3     0           0.3          10
#index is actually the index and not a column

Y:
Score
1
0.6
0.4

我使用嵌套交叉验证运行 xgboost 回归器,查看 MSE、预测 r2,并绘制观察值与预期值。我可以在观察到的与预期的图中看到,Y 中得分为 1 的基因具有模型预测的许多低分,我想了解为什么模型使用 shap 来执行此操作。很遗憾,我无法提供示例数据。

我正在尝试调整为标签分类给出的示例形状代码:

import shap

xgbr = xgboost.XGBRegressor()
xgbr.fit(X_train, Y_train)

select = range(8) #I have 8 features after feature selection with BorutaShap
features = X.iloc[select]
features_display = X.loc[features.index]

explainer = shap.TreeExplainer(xgbr)
expected_value = explainer.expected_value

#Example code from https://slundberg.github.io/shap/notebooks/plots/decision_plot.html: 

y_pred = xgbr.predict(X) 
y_pred = (shap_values.sum(1) + expected_value) > 0
misclassified = y_pred != y_test[select]
shap.decision_plot(expected_value, shap_values, features_display, link='logit', highlight=misclassified)

我如何选择 y_pred 以便预测/基因应该是 1 但实际上低于 0.8(或任何低数字)?

编辑:响应我尝试过的给定答案:

explainer = shap.TreeExplainer(xgbr)
shap_values = explainer.shap_values(X_test)

y_pred = xgbr.predict(X_test)
m = (y_pred <= 0.5) & (Y_test == 1)

shap.initjs()
shap.decision_plot(explainer.expected_value, shap_values,  X_test[m],  return_objects=True)

这会运行,但 m 的长度为 171(我的 Y_test 数据中的全部行数),然后该图绘制了所有 171 个它看起来的样子 - 我从查看数据中知道应该只有一个基因即

【问题讨论】:

    标签: python pandas machine-learning plot shap


    【解决方案1】:

    首先,你提到在回归分类中预测新基因的疾病评分,你是什么意思?输出似乎是二元的,01,因此这是一个二元分类问题。您应该改用xgboost 的分类器。 更新:让我们假设一个回归问题,根据 cmets,来模拟您的情况。虽然对于下面的示例,我们应该设置'objective':'multi:softmax' 来输出实际的标签。

    根据您的问题,您似乎要做的是在那些未正确预测的样本上索引测试集,并分析 误导 特征,这使得一个合理的意义。

    让我们用一些示例数据集重现您的问题:

    from sklearn.datasets import load_iris
    
    from sklearn.model_selection import train_test_split
    import shap
    import xgboost
    
    X,y = shap.datasets.iris()
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
    
    model = xgboost.train(params={"learning_rate": 0.01}, 
                          dtrain=xgboost.DMatrix(X_train, label=y_train), 
                          num_boost_round =100)
    

    使用整个测试集的 SHAP 图是直截了当的。以force_plot 为例:

    explainer = shap.TreeExplainer(model)
    shap_values = explainer.shap_values(X_test)
    
    shap.initjs()
    shap.force_plot(explainer.expected_value, shap_values, X_test)
    

    现在,如果我们想对错误分类的样本做同样的事情,我们需要查看输出概率。由于 iris 数据集有几个类,假设我们想要可视化那些本应归类为 2 的样本的 force_plot,但我们有一个低于 1.7 的输出值:

    y_pred = model.predict(xgboost.DMatrix(X_test))
    m = (y_pred <= 1.7) & (y_test == 2)
    

    现在我们使用掩码对X_test 集执行布尔索引,并更新shap_values

    shap.initjs()
    c= explainer.shap_values(X_test[m])
    shap.force_plot(explainer.expected_value, shap_values, X_test[m])
    

    这告诉我们,花瓣的长度和宽度主要将回归推向更高的值。因此,它们可能是在错误分类中起主要作用的变量。

    同样,对于decision_plot

    shap.decision_plot(explainer.expected_value, shap_values, 
                       X_test[m], feature_order='hclust', 
                       return_objects=True)
    

    【讨论】:

    • 谢谢你,这很有帮助。虽然我没有很好地解释我有一个回归,其中 Y 是 0-1 之间的任何值,所以虽然 1 是已知的疾病基因,但 0.74 是可能的疾病基因,0.17 是不太可能的基因,依此类推。我试过用我的数据运行你的代码,它在:IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match). 处出现错误 - 你知道我为什么会得到这个吗?同时我会继续努力
    • 这看起来像是索引导致的错误。确保您在y_testy_pred 上创建掩码,然后索引X_test @DN1
    • 布尔掩码必须正确尺寸。我使用y_predy_test 定义它,因为它们具有相同的形状。然后我可以用它来掩盖X_test,因为它也有相同的形状 @DN1
    • 谢谢你,我已经解决了这个错误并且一切正常,但m 似乎给了我所有的测试数据,而不仅仅是我正在寻找的低分基因 - 我'如果您可以查看我是否还缺少某些东西,我已经用详细信息更新了我的问题 - 也感谢您的所有帮助。
    • 是的。 mX_test 具有相同的形状。因为它是用来掩饰它的。但是,X_test[m] 将具有与 @DN1 掩码中的 Trues 一样多的值
    【解决方案2】:

    由于我没有你的数据集,我无法检查代码,但这里有一些想法可能会为你指明方向。

    看来你没有训练你的回归者。它应该像线

    xgbr = xgboost.XGBRegressor()
    xgbr.train(X, Y)
    

    现在你可以使用xgbr.predict(X) ;)

    你还需要训练解说员:

    explainer = shap.TreeExplainer(xgbr)
    with warnings.catch_warnings():
         warnings.simplefilter("ignore")
         sh = explainer.shap_values(X)
    

    现在你可以选择值了:

    misclassified = (y_pred <= 0.7) & (Y == 1)
    shap.decision_plot(expected_value, sh, features_display, link='logit', highlight=misclassified)
    

    在您使用shap 之前,我建议您检查一下您的回归器与您的数据的拟合程度。因此,为此我建议您在训练中使用部分数据进行测试。然后,您可以通过计算和比较测试集和训练集的 MSE 来评估拟合优度。差异越大,您的预测器执行得越差。

    【讨论】:

    • 谢谢你,看看misclassified 使用你的代码给我带来了什么,它是语句的行是 TRUE 还是 FALSE 的列表,至少对我来说将它发送到 decision_plot 不会不只是绘制错误分类。有没有办法通过获取整行来选择misclassified,而不仅仅是真/假(如果它们符合条件)?也很抱歉,我将在我的问题中添加更多细节,我查看具有 MSE 的模型并在嵌套交叉验证中预测 r2。我还绘制了观察到的与预期的对比图,它似乎在 Y=1 基因预测方面表现不佳。
    猜你喜欢
    • 2021-12-06
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多