PDP(Partial dependence plots)和 ICE(individual conditional expectation)可以用来分析预测目标和输入特征之间的相互关系。PDP和ICE假设我们要分析的特征和其他特征是独立的。
Partial Depentent Plot
PDP显示了一个或两个特征对机器学习模型的预测结果的边际效应。PDP可以显示目标和特征之间的关系是线性的、单调的还是更复杂的。 例如,当应用于线性回归模型时,PDP显示线性关系
对于回归函数来说 Partial Dependence function可以表示如下:
f ^ X s ( X s ) = E X c [ f ^ ( X s , X c ) ] = ∫ f ^ ( X s , X c ) p ( X c ) d X c \hat{f}_{X_s}(X_s) = E_{X_c}[\hat{f}(X_s, X_c)] = \int \hat{f}(X_s, X_c)p(X_c)dX_c f^Xs(Xs)=EXc[f^(Xs,Xc)]=∫f^(Xs,Xc)p(Xc)dXc
其中, X s X_s Xs是Partial Dependence 关注的特征, 而 X c X_c Xc是模型 f ^ \hat{f} f^中的其他特征. X s X_s Xs和 X c X_c Xc共同组成的特征空间 X X X. 通常来说 X s X_s Xs中只有一个或者两个特征.
Partial Dependence通过在 X c X_c Xc 中的特征分布上边缘化机器学习模型输出来工作,以便该函数显示我们感兴趣的 X S X_S XS 中的特征与预测结果之间的关系。 通过边缘化其他特征,我们得到一个仅依赖于 X S X_S XS 中的特征的函数,包括与其他特征的交互。
Partial function f ^ X s ( X s ) \hat{f}_{X_s}(X_s) f^Xs(Xs)通过计算训练集中的平均值来估计(mento carlo method):
f ^ X s ( X s ) = 1 n ∑ i = 1 n f ^ ( X s , X c ( i ) ) \hat{f}_{X_s}(X_s) = \frac{1}{n} \sum_{i=1}^n\hat{f}(X_s, X_c^{(i)}) f^Xs(Xs)=n1i=1∑nf^(Xs,Xc(i))
从Partial function中可以看出,对于给定的特征值 X S X_S XS, 对预测值的边际影响。 X c ( i ) X_c^{(i)} Xc(i)是数据集中我们不感兴趣的特征值。 n n n是数据集中的总样本数。PDP的一个假设是 X S X_S XS和 X C X_C XC是相互独立的,如果违反这一假设,则为PDP计算平均值的数据点将包含不可能的数据点,计算的平均值是不可信的。
对于分类问题来说,机器学习模型输出的是每个类别的概率。对于每一个类别,Partial Dependence会给出不同 X S X_S XS下的概率。可以为每个类别画出PDP。
使用PDP需要注意的问题
-
独立性假设是 PDP的最大问题。假设为其计算部分依赖的特征与其他特征不相关。例如,假设您想根据人的体重和身高预测他的步行速度。对于特征之一的部分依赖,例如身高,我们假设其他特征(体重)与身高无关,这显然是错误的假设。对于特定高度(例如 200 cm)的 PDP 计算,我们对重量的边际分布进行平均,其中可能包括低于 50 kg 的重量,这对于米的人来说是不现实的。换句话说:当特征相关时,我们会在特征分布的实际概率非常低的区域创建新的数据点(例如,不太可能有人身高 2 米但体重不到 50 公斤)。此问题的一种解决方案是使用条件分布而不是边际分布的累积局部效应图或短 ALE 图。
-
异质效应可能被隐藏,因为 PDP 仅显示平均边际效应。假设对于一个特征,你的数据点有一半与预测有正相关——特征值越大预测越大——而另一半有负相关——特征值越小预测越大。 PDP 曲线可能是一条水平线,因为数据集两半的影响可能会相互抵消。然后您得出结论,该特征对预测没有影响。通过绘制单独的条件期望曲线而不是聚合线,我们可以发现异质效应。
代码实践
sklearn.inspection提供了接口可以进行PDP分析
- two one-way PDPs for the features 0 and 1 and a two-way PDP between the two features
import matplotlib.pyplot as plt
from sklearn.datasets import make_hastie_10_2
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.inspection import plot_partial_dependence
X, y = make_hastie_10_2(random_state=0)
clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
max_depth=1, random_state=0).fit(X, y)
print(X.shape, y.shape) # (12000, 10) (12000,)
features = [0, 1, (0, 1)]
plot_partial_dependence(clf, X, features)
- For multi-class classification, you need to set the class label for which the PDPs should be created via the target argument
from sklearn.datasets import load_iris
iris = load_iris()
mc_clf = GradientBoostingClassifier(n_estimators=10,
max_depth=1).fit(iris.data, iris.target)
features = [1, 0, (3, 2)]
plot_partial_dependence(mc_clf, X, features, target=0)
- 对于非sklearn中的模型,就不能调用sklearn.inspection中的方法, 例如对于Xgboost中的模型,可以通过如下函数来看单个feature的PDP
import copy
from sklearn.datasets import load_iris
import xgboost as xgb
def partial_dependency(model, X, feature_ids=[], feature_names=None,f_id=-1, num_grids=50):
X_temp = copy.deepcopy(X)
X_grid = np.linspace(np.percentile(X_temp[:, f_id], 0.1),
np.percentile(X_temp[:, f_id], 99.9),
num_grids)
y_pred = np.zeros(len(X_grid))
for i, val in enumerate(X_grid):
X_temp[:, f_id] = val
data = xgb.DMatrix(X_temp[:, feature_ids], feature_names=feature_names)
y_pred[i] = np.average(model.predict(data))
return X_grid, y_pred
iris = load_iris()
X = iris.data
y = iris.target
params = {
'booster': 'gbtree',
'objective': 'multi:softmax',
'num_class': 3,
'gamma': 0.1,
'max_depth': 3,
'monotone_constraints': (-1,-1,0,-1)
}
dtrain = xgb.DMatrix(X, y)
model = xgb.train(params, dtrain, 10)
X_grid, y_pred = partial_dependency(model, X, feature_ids=[0,1,2,3], f_id=0)
plt.plot(X_grid, y_pred)
Individual Conditional Expectation plot(ICE)
ICE图为每个实例显示一条线,显示当特征发生变化时实例的预测如何变化。
特征平均效果的PDP是一种全局方法,因为它不关注特定样本,而是关注整体平均值。单个数据样本的 PDP 等效项称为单个条件期望 (ICE) 。 ICE 图分别可视化预测对每个实例的特征的依赖性,导致每个实例一条线,而部分依赖图中的一条线整体。 PDP 是 ICE 图线的平均值。一条线(和一个实例)的值可以通过保持所有其他特征相同来计算,通过用网格中的值替换特征值来创建此实例的变体,并使用黑盒模型对这些新创建的实例进行预测。结果是具有来自网格的特征值和相应预测的实例的一组点。
那么ICE的意义是什么呢。 PDP可以掩盖由相互作用产生的异质关系,可以显示特征和预测之间的平均关系, 但是这只适用于计算 PDP 的特征与其他特征之间的相互作用较弱的情况。 在特征相关性较强的情况下,ICE 会提供跟多的信息。
一个更加正式的定义是: 对于每个
{
(
x
S
(
i
)
)
,
x
C
(
i
)
)
}
i
=
1
N
\{ (x_S^{(i))}, x_C^{(i)}) \}_{i=1}^N
{(xS(i)),xC(i))}i=1N中的样本,
f
^
S
(
i
)
\hat{f}_S^{(i)}
f^S(i)是基于
X
s
i
X_s^{i}
Xsi画的,
x
C
(
i
)
x_C^{(i)}
xC(i)保持不变。
使用ICE需要注意的问题:
- ICE 曲线只能有意义地显示一个特征,因为两个特征需要绘制多个重叠曲面,可视化比较困难。
- ICE 曲线与 PDP 存在相同的问题:如果要分析的特征与其他特征相关,那么根据联合特征分布,线条中的某些点可能是无效数据点。
- 如果绘制了许多 ICE 曲线,则绘图可能会变得过于密集。 解决方案是为线条添加一些透明度或者仅绘制线条样本。
- 在 ICE 图中,查看平均值可能并不容易。 这有一个简单的解决方案是将ICE与PDP相结合。
代码实践
from sklearn.datasets import make_hastie_10_2
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.inspection import plot_partial_dependence
X, y = make_hastie_10_2(random_state=0)
clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
max_depth=1, random_state=0).fit(X, y)
features = [0, 1]
# use ICE plots alongside PDPs
plot_partial_dependence(clf, X, features, kind='both')
# plot_partial_dependence(clf, X, features, kind='individual')
参考文献:
- https://christophm.github.io/interpretable-ml-book/pdp.html
- https://scikit-learn.org/stable/modules/partial_dependence.html