Press "Enter" to skip to content

深入探讨模型可解释性的PFI

另一个解释性工具,增添你的工具箱

由fabio在Unsplash上的照片

作为数据科学家,了解如何评估模型对你的工作至关重要。如果你无法完全理解并向利益相关者进行沟通,没有人会签署你的解决方案。这就是为什么了解解释性方法如此重要。

缺乏解释性可能会毁掉一个非常好的模型。在我开发的模型中,我的利益相关者对了解预测是如何产生的总是感兴趣。因此,了解如何解释模型并将其传达给业务部门是数据科学家的基本能力。

在本文中,我们将探讨置换特征重要性(Permutation Feature Importance,PFI),这是一种与模型无关的方法,可以帮助我们确定模型中最重要的特征,从而更好地传达模型在进行预测时考虑的因素。

什么是置换特征重要性

置换特征重要性方法尝试根据将与目标变量相关的特征更改时模型的变化来估计特征对模型结果的重要性。

为了做到这一点,对于每个我们想要分析重要性的特征,我们在保持所有其他特征和目标变量不变的情况下对其进行随机置换。

这使得该特征无法预测目标变量,因为我们通过改变它们的联合分布破坏了它们之间的关系。

然后,我们可以使用我们的模型来预测我们的洗牌数据集。模型性能的降低程度将指示该特征的重要性。

算法大致如下:

  • 我们在训练数据集上训练一个模型,然后评估其在训练和测试数据集上的性能
  • 对于每个特征,我们创建一个特征被洗牌的新数据集
  • 然后,我们使用训练好的模型来预测新数据集的输出
  • 新性能指标除以旧性能指标给出我们的特征重要性

注意,如果一个特征不重要,模型的性能不应该有很大变化。如果有变化,那么模型的性能将大幅下降。

解释PFI

现在我们知道如何计算PFI,我们如何解释它呢?

这取决于我们应用PFI的折叠方式。通常,我们有两个选择:将其应用于训练集或测试集。

训练解释

在训练过程中,我们的模型学习数据的模式并尝试表示它。当然,在训练过程中,我们不知道我们的模型在未见数据上的泛化能力如何。

因此,通过将PFI应用于训练数据集,我们将看到哪些特征对模型对数据的表示的学习最重要。

从业务角度来看,这表明哪些特征对模型构建最重要。

测试解释

现在,如果我们将该方法应用于测试数据集,我们将看到特征对模型泛化的影响。

我们来想一下。如果我们在洗牌一个特征之后看到模型在测试集中的性能下降,这意味着该特征对该集的性能很重要。由于测试集是我们用来测试泛化性能的(如果你一切都做得对),所以我们可以说它对泛化很重要。

PFI的问题

PFI分析特征对模型性能的影响,因此它不对原始数据做任何陈述。如果你的模型性能不好,那么你在PFI中找到的任何关系都是没有意义的。

这对于两个集合都是正确的,如果你的模型欠拟合(在训练集上的预测能力低)或过拟合(在测试集上的预测能力低),那么你不能从这个方法中得到洞察。

此外,当两个特征高度相关时,PFI可能会误导你的解释。如果你洗牌一个特征,但所需信息被编码到另一个特征中,那么性能可能根本不会受到影响,这会让你认为该特征是无用的,而实际上可能不是这样。

Python中实现PFI

为了在Python中实现PFI,我们首先需要导入所需的库。在这里,我们主要使用numpy、pandas、tqdm和sklearn库:

import pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom tqdm import tqdmfrom sklearn.model_selection import train_test_splitfrom sklearn.datasets import load_diabetes, load_irisfrom sklearn.ensemble import RandomForestRegressor, RandomForestClassifierfrom sklearn.metrics import accuracy_score, r2_score

现在,我们需要加载数据集,这里使用的是鸢尾花数据集。然后,我们将对数据拟合一个随机森林模型。

X, y = load_iris(return_X_y=True)X_train, X_test, y_train, y_test = train_test_split(  X, y, test_size=0.3, random_state=12, shuffle=True)rf = RandomForestClassifier(  n_estimators=3, random_state=32).fit(X_train, y_train)

拟合好我们的模型后,让我们分析其性能,看看我们是否可以安全地应用PFI来观察特征对模型的影响:

print(accuracy_score(rf.predict(X_train), y_train))print(accuracy_score(rf.predict(X_test), y_test))

我们可以看到,在训练集上达到了99%的准确率,在测试集上达到了95.5%的准确率。目前看起来不错。让我们获取原始的错误得分以供以后比较:

original_error_train = 1 - accuracy_score(rf.predict(X_train), y_train)original_error_test = 1 - accuracy_score(rf.predict(X_test), y_test)

现在让我们计算排列得分。为此,通常对每个特征运行多次洗牌,以获得特征得分的统计数据,避免任何巧合。在我们的案例中,让我们对每个特征进行10次重复:

n_steps = 10feature_values = {}for feature in range(X.shape[1]):  # 我们将保存每个特征的每个新性能点    errors_permuted_train = []    errors_permuted_test = []        for step in range(n_steps):        # 我们再次获取数据,因为np.random.shuffle函数是原地洗牌的        X, y = load_iris(return_X_y=True)        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=12, shuffle=True)        np.random.shuffle(X_train[:, feature])        np.random.shuffle(X_test[:, feature])            # 将我们之前拟合的模型应用于新数据以获得性能        errors_permuted_train.append(1 - accuracy_score(rf.predict(X_train), y_train))        errors_permuted_test.append(1 - accuracy_score(rf.predict(X_test), y_test))            feature_values[f'{feature}_train'] = errors_permuted_train    feature_values[f'{feature}_test'] = errors_permuted_test

现在我们有一个字典,其中包含我们进行的每次洗牌的性能。现在,让我们生成一个表格,对于每个特征在每个折叠中,计算与我们模型的原始性能相比的平均值和标准差:

PFI = pd.DataFrame()for feature in feature_values:    if 'train' in feature:        aux = feature_values[feature] / original_error_train        fold = 'train'    elif 'test' in feature:        aux = feature_values[feature] / original_error_test        fold = 'test'        PFI = PFI.append({        'feature': feature.replace(f'_{fold}', ''),        'pfold': fold,        'mean':np.mean(aux),        'std':np.std(aux),    }, ignore_index=True)    PFI = PFI.pivot(index='feature', columns='fold', values=['mean', 'std']).reset_index().sort_values(('mean', 'test'), ascending=False)

我们最终会得到类似如下的结果:

我们可以看到,特征2似乎是我们数据集中最重要的特征,无论是在训练集还是测试集中,其次是特征3。由于我们没有固定numpy中洗牌函数的随机种子,我们可以预期这个数字会有所变化。

然后,我们可以将重要性绘制成图表,以更好地可视化重要性:

结论

PFI是一种简单的方法,可以帮助您快速确定最重要的特征。请尝试将其应用于您正在开发的某个模型,看看它的表现如何。

但也要注意方法的局限性。不知道方法的不足之处会导致您做出错误的解释。

此外,注意到PFI显示了特征的重要性,但并没有说明其对模型输出的影响方向。

那么,告诉我,您打算如何在下一个模型中使用这个方法呢?

敬请关注更多关于解释性方法的文章,这些方法可以改善您对模型的整体理解。

Leave a Reply

Your email address will not be published. Required fields are marked *