Skip to content

Latest commit

 

History

History
571 lines (340 loc) · 33.1 KB

4541.md

File metadata and controls

571 lines (340 loc) · 33.1 KB

解释性:破解黑箱,第二部分

原文

评论

Manu Joseph,问题解决者、从业者、Thoucentric Analytics 的研究员

上一篇文章中,我们定义了解释性是什么,并查看了一些可解释的模型以及它们的怪癖和“陷阱”。现在,让我们深入探讨事后解释技术,这在模型本身不透明时非常有用。这与大多数实际应用场景相呼应,因为无论我们喜欢与否,黑箱模型通常能提供更好的性能。


我们的前三个课程推荐

1. 谷歌网络安全证书 - 快速进入网络安全职业生涯。

2. 谷歌数据分析专业证书 - 提升你的数据分析水平

3. 谷歌 IT 支持专业证书 - 支持你的 IT 组织


数据集

对于本练习,我选择了成人数据集,即人口普查收入数据集。人口普查收入是一个相当受欢迎的数据集,包含年龄、职业等人口统计信息,以及一个列指示该人的收入是否超过 50k。我们使用这一列进行随机森林的二分类。选择随机森林的原因有两个:

  1. 随机森林是最常用的算法之一,与梯度提升树一样。它们都属于决策树的集成算法家族。

  2. 有一些特定于基于树的模型的技术,我想讨论。

人口普查收入数据集概述

人口普查收入数据集中的示例数据

事后解释

现在让我们来看一下事后解释技术,以理解我们的黑箱模型。在接下来的博客中,讨论将基于机器学习模型(而非深度学习)以及结构化数据。虽然这里许多方法是模型无关的,但由于解释深度学习模型,尤其是非结构化数据中的方法众多,我们将其排除在当前范围之外。(也许另一个博客,另一天。)

数据预处理

  • 将目标变量编码为数值变量

  • 处理了缺失值

  • 通过合并一些值将婚姻状况转换为二进制变量。

  • 去除了教育,因为教育年限提供了相同的信息,但以数字格式表示。

  • 去除了资本增益资本损失,因为它们没有提供任何信息。超过 90% 的值为零。

  • 去除了native_country,因为其基数较高且偏向美国。

  • 去除了关系,因为与婚姻状况有较多重叠。

随机森林算法在数据上进行调优和训练,性能达到 83.58%。考虑到最佳得分在 78%到 86%之间,这个得分还算不错,具体取决于你如何建模和测试。但对于我们的目的来说,模型性能已经足够。

1) 杂质减少的平均值

这是解释树模型及其集成的最流行方法。这在很大程度上归功于 Sci-Kit Learn,它提供了易于使用的实现。拟合随机森林或梯度提升模型并绘制“特征重要性”已经成为数据科学家中最常用且被滥用的技术。

特征的平均杂质减少重要性是通过测量特征在创建决策树时减少不确定性(分类器)或方差(回归器)的效果来计算的,适用于任何集成决策树方法(如随机森林、梯度提升等)。

该技术的优点是:

  • 获取特征重要性的快速简便方法

  • 在 Sci-kit Learn 和 R 的决策树实现中现成可用。

  • 向外行解释这一点相当直观。

算法

  • 在树的构建过程中,每当进行拆分时,我们会记录是哪个特征进行了拆分,拆分前后的基尼杂质是什么,以及它影响了多少样本。

  • 在树构建过程结束时,计算每个特征在基尼指数中所占的总增益。

  • 在随机森林或梯度提升树的情况下,我们将这个得分在所有树中取平均。

实现

Sci-kit Learn 默认在树模型的“特征重要性”中实现了这一点。因此,检索并绘制前 25 个特征非常简单。

feat_imp = pd.DataFrame({'features': X_train.columns.tolist(), "mean_decrease_impurity": rf.feature_importances_}).sort_values('mean_decrease_impurity', ascending=False)
feat_imp = feat_imp.head(25)
feat_imp.iplot(kind='bar',
               y='mean_decrease_impurity',
               x='features',
               yTitle='Mean Decrease Impurity',
               xTitle='Features',
               title='Mean Decrease Impurity',
              )

点击这里查看完整交互式图

我们还可以检索并绘制每棵树的杂质减少的均值作为箱形图。

# get the feature importances from each tree and then visualize the
# distributions as boxplots
all_feat_imp_df = pd.DataFrame(data=[tree.feature_importances_ for tree in
                                     rf],
                               columns=X_train.columns)
order_column = all_feat_imp_df.mean(axis=0).sort_values(ascending=False).index.tolist()

all_feat_imp_df[order_column[:25]].iplot(kind='box', xTitle = 'Features', yTitle='Mean Decease Impurity')

点击查看完整交互式图

解释

  • 排名前 4 的特征是婚姻状况、教育年限、年龄工作时长。这完全合乎逻辑,因为它们与收入的关系密切。

  • 注意到其中的两个特征 fnlwgt 和 random 吗?它们比一个人的职业更重要吗?

  • 另一个警告是,我们将 one-hot 特征视为单独的特征,这可能会影响为什么职业特征排名低于随机特征。处理 one-hot 特征时查看特征重要性是一个完全不同的话题。

让我们来看看 fnlwgt 和随机是什么。

  • 关于 fnlwgt 数据集的描述是关于人口普查机构如何使用采样来创建任何指定的社会经济特征的“加权统计”的冗长而复杂的描述。简而言之,它是一个采样权重,与个人收入无关。

  • 随机正如其名。在拟合模型之前,我制作了一列随机数字,并将其称为随机。

现在,这些特征不可能比其他特征,如职业、工作类别、性别等更重要。如果是这样的话,那就有问题了。

包中的小丑即“得逞”

当然……确实有。均值减少 impurity 测量是一个有偏的特征重要性测量。它偏向于连续特征和高基数特征。在 2007 年,Strobl et al [1] 也在 随机森林变量重要性测量中的偏差:插图、来源和解决方案 中指出,“Breiman 原始随机森林方法的变量重要性测量……在潜在预测变量在测量尺度或类别数量上有所不同的情况下是不可靠的。”

让我们尝试理解为什么它有偏差。记得如何计算 impurity 的均值减少吗?每当一个节点在某个特征上被拆分时,gini 指数的减少量会被记录下来。当一个特征是连续的或具有高基数时,这个特征可能会被拆分多于其他特征。这会夸大那个特定特征的贡献。我们的两个罪魁祸首特征有什么共同点——它们都是连续变量。

2) 删除列重要性即留一个协变量法 (LOOC)

删除列特征重要性是另一种直观的方法来查看特征重要性。顾名思义,这是一种迭代地删除一个特征并计算性能差异的方法。

该技术的优点包括:

  • 提供了每个特征预测能力的相当准确的图像。

  • 查看特征重要性的一个直观方式

  • 模型不可知。可以应用于任何模型。

  • 由于其计算方式,它会自动考虑模型中的所有交互。如果一个特征中的信息被破坏,它所有的交互也会被破坏。

算法

  • 使用你训练好的模型参数,在 OOB 样本上计算你选择的指标。你可以使用交叉验证来获得得分。这是你的基准线。

  • 现在,从你的训练集里每次删除一列,然后重新训练模型(使用相同的参数随机状态),并计算 OOB 得分。

  • 重要性 = OOB 得分 – 基线

实施

def dropcol_importances(rf, X_train, y_train, cv = 3):
    rf_ = clone(rf)
    rf_.random_state = 42
    baseline = cross_val_score(rf_, X_train, y_train, scoring='accuracy', cv=cv)
    imp = []
    for col in X_train.columns:
        X = X_train.drop(col, axis=1)
        rf_ = clone(rf)
        rf_.random_state = 42
        oob = cross_val_score(rf_, X, y_train, scoring='accuracy', cv=cv)
        imp.append(baseline - oob)
    imp = np.array(imp)

    importance = pd.DataFrame(
            imp, index=X_train.columns)
    importance.columns = ["cv_{}".format(i) for i in range(cv)]
    return importance

让我们进行 50 次交叉验证来估计我们的 OOB 得分。(我知道这有些过头,但让我们这样做以增加我们的箱线图样本)像以前一样,我们绘制了准确率的均值减少和箱线图,以了解交叉验证试验中的分布。

drop_col_imp = dropcol_importances(rf, X_train, y_train, cv=50)
drop_col_importance = pd.DataFrame({'features': X_train.columns.tolist(), "drop_col_importance": drop_col_imp.mean(axis=1).values}).sort_values('drop_col_importance', ascending=False)
drop_col_importance = drop_col_importance.head(25)
drop_col_importance.iplot(kind='bar',
               y='drop_col_importance',
               x='features',
               yTitle='Drop Column Importance',
               xTitle='Features',
               title='Drop Column Importances',
              )

all_feat_imp_df = drop_col_imp.T
order_column = all_feat_imp_df.mean(axis=0).sort_values(ascending=False).index.tolist()

all_feat_imp_df[order_column[:25]].iplot(kind='box', xTitle = 'Features', yTitle='Drop Column Importance')

点击查看完整互动图

点击查看完整互动图

解释

  • 前四个特征仍然是marital statuseducation_numagehours_worked

  • fnlwgt被排到列表的后面,现在排在一些 one-hot 编码的职业之后。

  • random仍然保持在高排名,紧跟在hours_worked之后

正如预期的那样,fnlwgt 的重要性远不如我们从“均值减少不纯度”中得出的结论。random的高排名让我有些困惑,我重新进行了重要性计算,将所有的 one-hot 特征视为一个特征。也就是说,删除所有的职业列,检查职业的预测能力。当我这样做时,我可以看到randomfnlwgt的排名低于occupationworkclass。为了避免让帖子变得更长,我们将这项调查留到另一日。

那么,我们是否得到了完美的解决方案?结果与“均值减少不纯度”一致,逻辑自洽,并且可以应用于任何模型。

包中的黑马

这里的关键是计算的复杂性。要进行这种重要性计算,你必须多次训练模型,每个特征训练一次,并对所需的交叉验证循环重复操作。即使你的模型在一分钟内完成训练,计算所需的时间也会随着特征数量的增加而爆炸。举个例子,我用 36 个特征和 50 次交叉验证循环计算特征重要性花了2 小时 44 分钟(当然,使用并行处理可以改善这一点,但你明白我的意思)。如果你的模型需要两天时间来训练,那么你可以忘记这种技术。

我对这种方法的另一个担忧是,由于我们每次都用新的特征集重新训练模型,因此我们并没有进行公平的比较。我们删除一列并再次训练模型,它会找到另一种方式来推导相同的信息(如果可以的话),当存在共线特征时,这种情况会被放大。因此,当我们进行调查时,我们混淆了特征的预测能力和模型如何配置自身。

3) 排列重要性

排列特征重要性被定义为当单个特征值随机打乱时模型分数的下降 [2]。这种技术测量如果你打乱特征向量,性能的差异。关键点在于,如果模型性能下降则该特征很重要。

这种技术的 优点 包括:

  • 直观易懂。打乱特征信息后,性能下降多少?

  • 模型无关。尽管这种方法最初是由 Breiman 为随机森林开发的,但很快被适应到一个模型无关的框架中。

  • 计算方式会自动考虑模型中的所有交互。如果一个特征中的信息被破坏,那么所有与之相关的交互也会被破坏。

  • 模型不需要重新训练,因此我们节省了计算资源。

算法

  • 使用指标、训练模型、特征矩阵和目标向量计算基线分数。

  • 对于特征矩阵中的每个特征,复制特征矩阵。

  • 打乱特征列,通过训练模型进行预测,并使用指标计算性能。

  • 重要性 = 基线 – 分数

  • 为了统计稳定性,重复 N 次,并计算试验的平均重要性。

实现

排列重要性在 Python 的至少三个库中实现—— ELI5, mlxtend,以及在 Sci-kit Learn 的开发分支 中。我选择了 mlxtend 版本纯粹是因为便利。根据 Strobl et al. [3],“原始 [排列] 重要性… 具有更好的统计特性。” 而不是通过标准差来规范化重要性值。我已经检查了 mlxtend 和 Sci-kit Learn 的源代码,它们没有对其进行规范化。

from mlxtend.evaluate import feature_importance_permutation
#This takes sometime. You can reduce this number to make the process faster
num_rounds = 50
imp_vals, all_trials = feature_importance_permutation(
    predict_method=rf.predict, 
    X=X_test.values,
    y=y_test.values,
    metric='accuracy',
    num_rounds=num_rounds, 
    seed=1)
permutation_importance = pd.DataFrame({'features': X_train.columns.tolist(), "permutation_importance": imp_vals}).sort_values('permutation_importance', ascending=False)
permutation_importance = permutation_importance.head(25)
permutation_importance.iplot(kind='bar',
               y='permutation_importance',
               x='features',
               yTitle='Permutation Importance',
               xTitle='Features',
               title='Permutation Importances',
              )

我们还绘制了所有试验的箱型图,以了解偏差情况。

all_feat_imp_df = pd.DataFrame(data=np.transpose(all_trials),
                               columns=X_train.columns, index = range(0,num_rounds))
order_column = all_feat_imp_df.mean(axis=0).sort_values(ascending=False).index.tolist()

all_feat_imp_df[order_column[:25]].iplot(kind='box', xTitle = 'Features', yTitle='Permutation Importance')

点击查看完整交互式图表

点击查看完整交互式图表

解释

  • 前 4 名保持不变,但前三个(marital_status, education, age)在排列重要性中更加突出。

  • fnlwgtrandom 连前 25 名都未能进入。

  • 成为 Exec ManagerProf-speciality 与是否能赚取超过 50k 的收入关系密切。

  • 总的来说,这与我们对过程的心理模型相吻合。

特征重要性领域一切都很美好吗?我们是否找到了最好的方式来解释模型用于预测的特征?

包中的小丑

从生活中我们知道,任何事物都不完美,这项技术也不例外。它的致命弱点是特征之间的相关性。就像删除列重要性一样,这项技术也受到特征间相关性影响。Strobl et al. 在《随机森林中的条件变量重要性》中[3] 表示“置换重要性高估了相关预测变量的重要性”。特别是在树的集成中,如果有两个相关变量,某些树可能选择特征 A,而其他树可能选择特征 B。在进行此分析时,如果没有特征 A,那么选择特征 B 的树会表现良好并保持高性能,反之亦然。这将导致相关特征 A 和 B 的重要性都被夸大。

这项技术的另一个缺点是其核心思想在于置换特征。但这本质上是我们无法控制的随机性。因此,结果可能会有很大差异。虽然我们在这里没有看到,但如果箱型图显示特征在各次试验中的重要性变化很大,我会在解释时保持警惕。

相关系数 [7](内置于 pandas profiling 中,也考虑了分类变量)。

这项技术还有另一个缺点,在我看来,这是最令人担忧的。Giles Hooker 等人[6] 说,“当训练集中的特征表现出统计依赖性时,置换方法在应用于原始模型时可能会非常误导。”

让我们考虑职业教育。我们可以从两个角度来理解这一点:

  1. 逻辑:如果你仔细考虑,职业教育之间有明确的依赖性。如果你有足够的教育,你能找到的工作也就有限,从统计学上看,你可以在它们之间画出相似之处。因此,如果我们对这些列中的任何一列进行置换,就会创建一些没有意义的特征组合。一个教育10 年级职业专业的人并没有太大意义,对吧?因此,当我们评估模型时,我们评估的是像这样的无意义情况,这会混淆我们用来评估特征重要性的指标。

  2. 数学职业教育之间有很强的统计依赖性(我们可以从上面的相关性图中看到)。因此,当我们对这些特征中的任何一个进行置换时,我们实际上是在强迫模型探索高维特征空间中未见过的子空间。这迫使模型进行外推,而这种外推是一个显著的误差来源。

Giles Hooker 等人 [6] 建议使用结合了 LOOC 和置换方法的替代方法,但所有这些替代方法在计算上更为密集,并且没有强有力的理论保证其具有更好的统计性质。

处理相关特征

识别出高度相关的特征后,有两种处理相关特征的方法。

  1. 将高度相关的变量分组,并仅从该组中评估一个特征作为该组的代表。

  2. 当你置换列时,一次试验中要置换整个特征组。

注意:第二种方法与我建议处理一热变量的方法相同。

附注(训练集或验证集)

在讨论 Drop Column 重要性和置换重要性时,你应该想到一个问题。我们将测试/验证集传递给这些方法来计算重要性。为什么不使用训练集呢?

这是应用某些方法的灰色地带。这里没有对错之分,因为两者都有利弊。在《可解释机器学习》中,Christoph Molnar 为训练集和验证集的使用都提出了论据。

对于测试/验证数据的情况是不言而喻的。由于我们不通过训练集中的误差来评估模型,因此也不能通过训练集上的表现来评估特征的重要性(尤其是因为重要性本质上与误差相关)。

对于训练数据的情况是违反直觉的。但如果你考虑一下,你会发现我们想要测量的是模型如何使用特征。还有什么比训练集更适合判断这一点的数据呢?另一个显而易见的问题是,我们理想情况下会在所有可用数据上训练模型,在这种理想情况下,不会有测试或验证数据来检查性能。在《可解释机器学习》 [5] 中,第 5.5.2 节对此问题进行了详细讨论,甚至提供了一个过拟合 SVM 的合成示例。

这归结于你是否想知道模型依赖哪些特征来进行预测,还是每个特征在未见数据上的预测能力。例如,如果你在特征选择的背景下评估特征重要性,任何情况下都不应使用测试数据(因为这会使你的特征选择过度拟合测试数据)。

4) 部分依赖图(PDP)和个体条件期望图(ICE)

我们到目前为止审查的所有技术都关注于不同特征的相对重要性。现在让我们稍微改变方向,看看一些技术,这些技术探索了某个特征如何与目标变量互动。

部分依赖图和个体条件期望图帮助我们理解特征与目标之间的函数关系。它们是给定变量(或多个变量)对结果的边际效应的图形可视化。Friedman(2001)在他的开创性论文贪婪函数逼近:一种梯度提升机器中介绍了这一技术。

部分依赖图显示了平均效应,而 ICE 图显示了单个观察的函数关系。PD 图显示平均效应,而 ICE 图显示效应的离散性或异质性。

这一技术的优点包括:

  • 计算非常直观,并且容易用通俗的语言解释。

  • 我们可以理解特征或特征组合与目标变量之间的关系,即是否是线性、单调、指数等。

  • 它们计算和实现起来很简单。

  • 它们提供了因果解释,而不是特征重要性风格的解释。但我们需要记住的是,模型对世界的因果解释与现实世界的因果解释之间的差异。

算法

让我们考虑一个简单的情况,即我们绘制单个特征x的 PD 图,包含唯一值 {x_1, x_2, .... x_n}。PD 图可以按如下方式构建:

  • 对于 i: \epsilon : {1,2,...k}

    • 复制训练数据并用 x_i 替换原始的 x 值。

    • 使用训练好的模型生成修改后的整个训练数据的预测值。

    • 将所有关于 x_i 的预测存储在类似地图的数据结构中。

  • 对于 PD 图:

    • 计算每个 x_i : for : i : \epsilon : {1,2,...k} 的平均预测值。

    • 绘制对 ![{x_i, mean(all: predictions :with: x_i)}](img/: x_i)}")。

  • 对于 ICE 图:

    • 绘制所有对 {x_i, f(x_i,rest:of:features)_n} :where:n\epsilon{1, 2, ...N}_n} :where:n\epsilon{1, 2, ...N}")。N 是训练集中的总观察数。
  • 在实践中,为了节省计算时间,我们定义一个连续变量的区间网格,而不是取特征的所有可能值。

  • 对于分类变量,这一定义也适用,但我们不会在这里定义网格。相反,我们取所有唯一的分类值(或与分类特征相关的所有独热编码变量),并使用相同的方法计算 ICE 和 PD 图。

  • 如果过程对你仍然不清楚,我建议查看这个medium post(由 PDPbox 的作者编写,这是一个用于绘制 PD 图的 python 库)。

实施

我发现了在PDPboxskaterSci-kit Learn中实现的 PD 图。以及在PDPboxpyCEboxskater中的 ICE 图。在这些工具中,我发现 PDPbox 是最精致的,它们还支持 2 变量 PDP 图。

from pdpbox import pdp, info_plots
pdp_age = pdp.pdp_isolate(
    model=rf, dataset=X_train, model_features=X_train.columns, feature='age'
)
#PDP Plot
fig, axes = pdp.pdp_plot(pdp_age, 'Age', plot_lines=False, center=False, frac_to_plot=0.5, plot_pts_dist=True,x_quantile=True, show_percentile=True)
#ICE Plot
fig, axes = pdp.pdp_plot(pdp_age, 'Age', plot_lines=True, center=False, frac_to_plot=0.5, plot_pts_dist=True,x_quantile=True, show_percentile=True)

年龄的 ICE 图。

让我花点时间来解释这个图。x 轴显示了你想要理解的特征的值,即年龄。y 轴显示了预测值。在分类的情况下,它是预测概率,而在回归的情况下,它是实际值预测。底部的条形图表示训练数据点在不同分位数的分布。它帮助我们评估推断的好坏。在点数很少的地方,模型看到的例子较少,解释可能会很棘手。PD 图中的单一线条显示了特征与目标之间的平均功能关系。ICE 图中的所有线条显示了训练数据中的异质性,即训练数据中所有观察值如何随年龄的不同值变化。

解释

  • 年龄与一个人的收入能力有着基本单调的关系。一个人越老,收入超过 50k 的可能性越大。

  • ICE 图显示了很多离散度。但所有的离散度都表现出我们在 PD 图中看到的相同行为。

  • 训练观察在不同分位数之间相当平衡。

现在,我们还可以用一个分类特征,如教育,来举例说明。PDPbox 有一个很好的功能,允许你传递一个特征列表作为输入,它会将这些特征视为分类特征来计算 PDP。

# All the one-hot variables for the occupation feature
occupation_features = ['occupation_ ?', 'occupation_ Adm-clerical', 'occupation_ Armed-Forces', 'occupation_ Craft-repair', 'occupation_ Exec-managerial', 'occupation_ Farming-fishing', 'occupation_ Handlers-cleaners', 'occupation_ Machine-op-inspct', 'occupation_ Other-service', 'occupation_ Priv-house-serv', 'occupation_ Prof-specialty', 'occupation_ Protective-serv', 'occupation_ Sales', 'occupation_ Tech-support', 'occupation_ Transport-moving']
#Notice we are passing the list of features as a list with the feature parameter
pdp_occupation = pdp.pdp_isolate(
    model=rf, dataset=X_train, model_features=X_train.columns, 
    feature=occupation_features
)
#PDP
fig, axes = pdp.pdp_plot(pdp_occupation, 'Occupation', center = False, plot_pts_dist=True)
#Processing the plot for aesthetics
_ = axes['pdp_ax']['_pdp_ax'].set_xticklabels([col.replace("occupation_","") for col in occupation_features])
axes['pdp_ax']['_pdp_ax'].tick_params(axis='x', rotation=45)
bounds = axes['pdp_ax']['_count_ax'].get_position().bounds
axes['pdp_ax']['_count_ax'].set_position([bounds[0], 0, bounds[2], bounds[3]])
_ = axes['pdp_ax']['_count_ax'].set_xticklabels([])

解释

  • 大多数职业对你的收入影响非常有限。

  • 从中突出的有,Exec-managerial、Prof-speciality 和 Tech Support。

  • 但是,从分布来看,我们知道 Tech-support 的训练示例非常少,因此我们对此持保留态度。

多个特征之间的交互

理论上,可以为任意数量的特征绘制 PD 图以展示它们的交互效应。但实际上,我们最多只能做两个,最多三个。让我们看看两个连续特征年龄教育之间的交互图(教育和年龄并不真正连续,但为了缺乏更好的例子我们选择它们)。

你可以用两种方式绘制两个特征之间的 PD 图。这里有三个维度,特征值 1,特征值 2 和目标预测。我们可以绘制 3D 图或将第三维度表现为颜色的 2D 图。我更喜欢 2D 图,因为我认为它比 3D 图更清晰,3D 图需要查看 3D 形状以推断关系。PDPbox 实现了 2D 交互图,既有轮廓图也有网格图。轮廓图最适合连续特征,网格图适合分类特征。

# Age and Education
inter1 = pdp.pdp_interact(
    model=rf, dataset=X_train, model_features=X_train.columns, features=['age', 'education_num']
)
fig, axes = pdp.pdp_interact_plot(
    pdp_interact_out=inter1, feature_names=['age', 'education_num'], plot_type='contour', x_quantile=False, plot_pdp=False
)
axes['pdp_inter_ax'].set_yticklabels([edu_map.get(col) for col in axes['pdp_inter_ax'].get_yticks()])

解释

  • 即使我们观察到年龄与单独看时的单调关系,现在我们知道这并非普遍。例如,看看12教育水平右侧的轮廓线。与一些大学及以上的线相比,它相当平坦。这实际上表明,你获得超过 50k 的概率不仅随着年龄增长而增加,还与教育有关。大学学位确保了你随着年龄的增长增加收入潜力。

这也是调查算法中的偏见(伦理类型)非常有用的技术。假设我们想查看性别维度中的算法偏见。

#PDP Sex
pdp_sex = pdp.pdp_isolate(
    model=rf, dataset=X_train, model_features=X_train.columns, feature='sex'
)
fig, axes = pdp.pdp_plot(pdp_sex, 'Sex', center=False, plot_pts_dist=True)
_ = axes['pdp_ax']['_pdp_ax'].set_xticklabels(sex_le.inverse_transform(axes['pdp_ax']['_pdp_ax'].get_xticks()))

# marital_status and sex
inter1 = pdp.pdp_interact(
    model=rf, dataset=X_train, model_features=X_train.columns, features=['marital_status', 'sex']
)
fig, axes = pdp.pdp_interact_plot(
    pdp_interact_out=inter1, feature_names=['marital_status', 'sex'], plot_type='grid', x_quantile=False, plot_pdp=False
)
axes['pdp_inter_ax'].set_xticklabels(marital_le.inverse_transform(axes['pdp_inter_ax'].get_xticks()))
axes['pdp_inter_ax'].set_yticklabels(sex_le.inverse_transform(axes['pdp_inter_ax'].get_yticks()))

左侧是性别的 PD 图,右侧是性别与婚姻状况的 PD 交互图。

  • 如果我们仅查看性别的 PD 图,我们会得出结论,没有基于性别的真实歧视。

  • 不过,只需看看与婚姻状况的交互图。左侧(已婚),两个方块的颜色和值相同,但右侧(单身)则存在女性和男性之间的差异。

  • 我们可以得出结论,单身男性比单身女性获得超过 50k 的机会要大得多。(虽然我不会基于此对性别歧视发动全面战争,但它肯定是调查的一个起点。)

包装中的小丑

特征之间的独立性假设是该方法最大的缺陷。LOOC 重要性和置换重要性中存在的相同缺陷也适用于 PDP 和 ICE 图。累积局部效应图是解决此问题的方案。ALE 图通过计算——同样基于特征的条件分布——预测差异而非平均值来解决这个问题。

总结每种图(PDP,ALE)如何计算特征在某个网格值 v 上的影响:

部分依赖图:“让我展示当每个数据实例在该特征上具有值 v 时,模型平均预测结果。我忽略了值 v 对所有数据实例是否合理。”

ALE 图:“让我展示在该窗口内的数据实例的特征值 v 附近,模型预测如何在特征的一个小‘窗口’中变化。”

在 Python 环境中,没有好的稳定的 ALE 库。我只找到一个ALEpython,仍在开发中。我设法获得了年龄的 ALE 图,如下所示。但在尝试绘制交互图时出现了错误。它也没有针对分类特征进行开发。

年龄的 ALE 图。

这里我们再次分开,将其余内容推迟到下一个博客帖子。在下一部分,我们将查看 LIME、SHAP、Anchors 等。

完整代码可以在我的Github上找到。

原文。经许可转载。

简介:Manu Joseph (@manujosephv) 是一位天生好奇的自学数据科学家,拥有超过 8 年的专业经验,曾在财富 500 强公司工作,包括Thoucentric分析公司的研究员。

相关:

更多相关主题