如何使用SHAP分析机器学习模型

859 阅读13分钟

如何使用SHAP分析机器学习模型

可解释的人工智能描述了机器学习模型的一般结构。它分析了模型的特征和属性如何影响模型的结果。

模型分析确定了模型在进行预测时的逻辑推理,并解释了模型做出的决定。分析这些预测结果的概念被称为可解释人工智能。可解释的人工智能使我们能够理解所做的预测结果,并在使用模型时建立起信任和信心。

在生产过程中,我们必须有一个可以信任的模型。如果一个模型在生产中失败了,可能会对商业运作产生很大影响。这导致了业务损失。

在本教程中,我们将首先建立一个糖尿病预测模型。然后我们将使用SHAP来分析和解释这个模型做出的预测结果。

前提条件

为了理解本教程,读者应该。

  • 在自己的机器上安装[Python]。
  • 理解[Python编程。]
  • 知道如何使用[Scikit-learn]建立[机器学习模型]。
  • 知道如何使用[谷歌colab笔记本]进行项目。
  • 知道如何使用[Pandas]和[Numpy]进行机器学习。

可解释的人工智能的重要性

原因如下。

  1. 了解模型的内部功能和决策过程。通过可解释人工智能,我们可以了解模型的内部功能。它让我们更深入地了解这些模型是如何做出决定的。它使用户能够理解用于做出这些决定的标准。
  2. 减少模型的偏差。在分析机器学习模型时,我们选择最好的功能来建立模型。这就减少了模型在预测过程中做出的偏差。
  3. 提高模型性能。它通过选择最佳特征进行预测来提高模型性能。
  4. 有助于模型调试。通过模型调试,它可以消除模型中的缺陷和错误。
  5. 识别错误的预测。可解释的人工智能确定了模型所做的错误预测。作出错误预测的模型将不会被部署到生产中。

让我们开始处理我们的数据集。

建模数据集

收集的数据集包含糖尿病患者和非糖尿病患者的信息。这个数据集将被用来训练我们的模型。

我们的模型将从这个数据集中学习,了解模式。该模型将从经验中改进。它最终会使用这些信息来进行预测。

让我们看一下这个数据集。

Dataset image

从上面的图片来看,我们的图片没有列名或标题。为了添加列名或标题,我们导入探索性数据分析(EDA)包。

导入探索性数据分析包

我们将导入两个包,Pandas和Numpy。

我们使用Pandas来导入我们的数据集。它还将列名添加到我们的数据集中。Numpy将被用于数学运算。

让我们来初始化我们的列名。

初始化列名

我们初始化列名如下。

names = ["Num_of_Preg","Glucose_Conc","BP","Skin_Thickness","TwoHour_Insulin","BMI","DM_Pedigree","Age","Class"]

上面显示的名字是从病人身上收集的信息。这些信息用于确定一个人是糖尿病患者还是非糖尿病患者。

让我们把这些名字添加到我们的数据集中。

df = pd.read_csv("diabetes-prediction.csv",names=names)

从上面的代码中,我们已经用Pandas导入了我们的数据集。它还添加了初始化的列名。让我们看看这些列名是否已经被添加到我们的数据集中。

df.head()

Dataset image

让我们检查一下我们的数据集中是否有缺失的值。

检查缺失值

为了检查缺失值,运行这个命令。

df.isna().sum()

让我们看看输出结果。

Missing values

从上面的图片来看,我们没有任何缺失值。这表明,所有的数据点都是可用的。从这里,我们可以检查我们的数据集列的数据类型。

检查我们的数据类型

要检查数据类型,请使用这段代码。

df.dtypes

输出显示如下。

Data types

从上面的图片中,我们有两个数据类型:int64float64 。这些都是数字,这些表明我们的数据类型是统一的。

注意:所有的数据类型都必须是数字。与其他数据类型相比,数字更容易被机器读取。如果你发现你的数据类型不是数字,你需要把它们转换成int64 或`float64。

我们的数据集包含糖尿病患者和非糖尿病患者的信息。让我们看看他们在我们的数据集中是如何分布的。

糖尿病患者与非糖尿病患者

要检查这些数字,请运行这个命令。

df.groupby('Class').size()

输出如下图所示。

Class
0    500
1    268
dtype: int64

从输出结果来看,我们有两个类别010 代表非糖尿病患者,而1 代表糖尿病患者。

从数字中我们可以看到我们有500 非糖尿病患者和268 糖尿病患者。

我们需要添加糖尿病患者和非糖尿病患者的信息。这使得模型可以从他们两个人身上学习。这有助于减少模型的偏差。

添加特征和标签

特征是数据集中的独特属性和变量。它们被用作模型的输入。在训练阶段,特征将训练我们的模型。

标签是目标或输出变量。标签是模型在预测阶段试图预测的东西。

从我们的数据集中,我们有8 特征。它们是。Num_of_Preg,Glucose_Conc,BP,Skin_Thickness,TwoHour_Insulin,BMI,DM_PedigreeAge

让我们来添加这些特征。

df.iloc[:,0:8]

我们使用iloc ,从我们数据集的0 索引中选择到8 索引。

输出结果如下图所示。

Features

上图显示了所有添加到我们数据集的8 特征。我们现在将这些特征保存到一个叫做Xfeatures 的变量中。

Xfeatures = df.iloc[:,0:8]

现在我们来添加我们的标签。

我们的标签是class 列。class 列被标记为100 代表非糖尿病患者,而1 代表糖尿病患者。

Ylabels = df['Class']

现在让我们来缩放我们的数据集。

数据集的缩放

数据集缩放确保我们的数据集符合模型的要求。它使用一个指定的比例去除重叠的数据集。它还将int64 的所有输入数据类型转换为float64

让我们导入将用于缩放我们的数据集的Python包。

from sklearn.preprocessing import MinMaxScaler as Scaler

MinMaxScaler 将被用于缩放我们的数据集。

关于MinMaxScaler 如何工作的进一步阅读,请阅读这篇文章

由于我们要缩放输入变量,我们将缩放我们的Xfeatures 。让我们运行这段代码来扩展我们的Xfeatures

scaler = Scaler()
X = scaler.fit_transform(Xfeatures)

从上面的代码中,我们已经将我们的缩放器函数初始化为Scaler() 。我们还使用了fit_transform 方法。它确保我们的Xfeatures 在训练阶段适合于模型。

然后,我们需要将我们的缩放数据集转换为一个数据框架。数据框架将把我们的数据集结构成行和列,如下图所示。

X = pd.DataFrame(X,columns=names[0:8])

要查看我们的缩放数据框架,请运行这个命令。

X.head()

其输出结果如下。

Data frame

现在我们来分割我们的数据集。

分割我们的数据集

我们把数据集分成两组,训练集和测试集。训练集是在训练阶段使用的。模型从这个数据集中学习。

测试集被用来评估模型的性能。它也衡量模型的准确度。

让我们导入将我们的数据集分成两部分所需的包。

from sklearn.model_selection import train_test_split

我们使用train_test_split 来分割我们的数据集。

X_train,X_test,y_train,y_test = train_test_split(X,Ylabels,test_size=0.2,random_state=42)

在上面的代码中,我们使用了test_size=0.2 。这意味着,80% 将被用作训练集。剩下的20% 将是测试集。

让我们开始建立我们的模型。

建立模型

让我们从导入机器学习包开始。

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

如上所示,我们已经导入了以下内容。

  • LogisticRegression。这是用来训练我们模型的算法。

  • accuracy_score。这个方法是用来计算模型在进行预测时的准确度分数。

现在让我们使用LogisticRegression 算法建立模型。

logit = LogisticRegression()
logit.fit(X_train,y_train)

在上面的代码中,我们已经将我们的算法初始化为LogisticRegression() 。然后我们使用fit() 方法将我们的模型拟合到训练集中。

该模型将从训练集中学习并理解模式。它也会从经验中改进。它最终会使用它获得的信息来进行预测。

让我们计算一下这个模型的准确度得分。

计算准确率得分

我们使用accuracy_score 来计算准确率分数。

print("Accuracy Score of Logistic::",logit.accuracy_score(X_test,y_test))

准确率得分如下所示。

Accuracy Score of Logistic:: 0.7727272727272727

当转换为百分比时是77.27% 。随着我们继续训练我们的模型,准确率分数将增加。

测试我们的模型

在这个阶段,我们使用我们的模型来进行预测。我们的模型应该预测一个给定的输入样本是否属于糖尿病患者或非糖尿病患者。

让我们从测试集中提取一个输入样本。样本输入是测试集数据集的第一个数据点。它由数组的0 索引表示。

X_test.values[0]

样本输入的值如下所示。

array([0.35294118, 0.3483871 , 0.34693878, 0.33333333, 0.22458629,
       0.32310838, 0.15029889, 0.36666667])

现在让我们用这些值做一个单一的预测。

进行单一的预测

为了进行预测,我们使用predict() 方法,如下所示。

logit.predict(np.array(X_test.values[0]).reshape(1,-1))

我们还使用np.array 来读取数组的第一个索引。然后,我们使用reshape(1,-1) ,在一个单列中输出预测结果。

让我们看看预测结果。

array([0])

预测结果是0 。这表明输入的样本属于非糖尿病患者。

我们现在需要解释这个预测结果。这使我们能够看到模型为什么以及如何得出这个结论。

让我们开始使用SHAP。

开始使用SHAP

沙普利加法解释(SHAP)是一种用于分析结果的博弈论技术。它可以解释机器学习模型的预测结果。它使用Shapley值。

Shapley值是分配给模型特征的权重。它显示了每个特征对预测结果的贡献。它确定了特征对预测结果的影响。

让我们来安装SHAP。我们可以用以下命令安装SHAP。

!pip install shap

让我们导入SHAP。

import shap

我们还需要初始化JavaScript。JavaScript使我们能够绘制可视化的图表。SHAP使用不同的绘图技术来解释预测结果。

初始化JavaScript

shap.initjs()

现在让我们开始解释预测结果。我们使用KernelExplainer 函数来解释上面的预测结果。KernelExplainer 是SHAP的一个函数,与LogisticRegression 算法配合得很好。

让我们来初始化KernelExplainer 这个函数。

初始化KernelExplainer

我们需要向我们的训练集添加KernelExplainer ,以便从数据集中学习。这使得该函数更容易解释预测结果。

explainer = shap.KernelExplainer(logit.predict_proba, X_train)

在上面的代码中,我们已经传递了X_train 。这使得KernelExplainer 能够理解模式。我们还指定使用的算法为logitlogit 代表LogisticRegression 算法。

从这里,我们现在可以创建Shapley值。Shapley值将为数据集中的可用特征分配权重。

创建Shapley值

这段代码将创建输入样本中的Xfeatures 的Shapley值。我们使用的是上一节的输入样本。我们将解释在这个实例中所作的预测。

shap_values = explainer.shap_values(X_test.iloc[0,:])

要查看生成的Shapley值,请运行此命令。

X_test.iloc[0,:]

生成的Shapley值如下所示。

Shapley Values

我们现在使用这些生成的值来绘制一个力图图。

力曲线图

力量图是一种图表,它直观地显示了每个特征对预测结果的贡献。它们让人们直观地了解权重是如何影响预测结果的。

要绘制一个力图图,请运行这个命令。

shap.force_plot(explainer.expected_value[0], shap_values[0], X_test.iloc[0:])

绘图函数有以下参数。

  • expected_value[0]

这代表了用来进行预测的输入样本。在上一节中,我们用同样的输入样本来进行预测。

输入的样本是测试集的第一个数据点。它由数组中的0 索引表示。SHAP将解释为什么这个输入样本被预测为非糖尿病患者。

  • shap_values[0]

我们指定shapely值为0 。这就选择了有助于非糖尿病患者预测的形体值。

  • X_test.iloc[0:]

iloc 方法选择X_test 数组中的第1个数据点。

力图的输出如下所示。

Force plot

我们来分析一下这个力图。

分析受力图

受力图有以下属性。

基本值

这是训练阶段后的平均预测概率。在我们的例子中,基值是0.67 。这个值是用来确定预测是真的还是假的。

如果我们得到的输出值低于0.67 ,这将意味着我们的模型有一个错误的预测。然而,如果我们得到一个等于或大于0.67 的值,这将意味着模型做出了正确的预测。

输出值

这是训练后的真实预测值。在我们的例子中,输出值是0.70

分配的特征权重和值

它们对预测得分的贡献是0.70。这个值用粗体字显示。

红色块

这代表对预测结果有积极影响的特征。它们将预测结果从基础值0.67 推向输出值 。0.70

从上面的图片中,我们有一些特征,如:TwoHour_InsulinGlucose_Conc

蓝色块

这代表对预测结果有负面影响的特征。它们试图将预测值从基础值0.67

色块的大小

色块的大小代表特征的重要性。尺寸越大,该特征对预测结果的影响越大。

例如,在红色色块中,Glucose_Conc 的大小最大。这表明它对预测结果有较大的影响。

在蓝色的色块中,Age ,影响最大。

从上面的力图中,我们可以得出以下结论。

  • 我们的模型能够做出正确的预测。

这是因为Output value0.70 。这个值高于0.67 的基础值。

我们还可以使用总结图。总结图是用来显示所有特征对预测结果的贡献。

绘制摘要图

要绘制一个摘要图,请使用这段代码。

shap.summary_plot(shap_values,X_test)

总结图的输出如下所示。

Summary plot

从摘要图中,我们可以看到,Glucose_Conc 的影响最大。Skin_Thickness 的影响最小。

现在我们已经成功地分析了我们的预测结果。

要获得本教程的Google Colab链接,请点击这里

结论

在本教程中,我们学习了如何使用SHAP来分析机器学习模型。我们首先学习了分析机器学习预测结果的重要性。这有助于人类在使用模型时的信任和信心。

然后我们转向数据集的预处理。这涉及到清理我们的数据,以确保没有缺失值。它还涉及缩放数据集,以确保它适合。在这之后,我们能够建立一个机器学习模型。该模型能够预测一个病人是否患有糖尿病。

最后,我们用SHAP来解释我们模型的预测结果。经过分析,我们得出结论,我们的模型做出了正确的预测。这是因为输出值高于基础值。