PCA 中特征重要性的度量

Measure of Feature Importance in PCA

我正在进行主成分分析 (PCA),我想找出对结果贡献最大的特征。

我的直觉是总结特征对各个组件的各个贡献的所有绝对值。

import numpy as np
from sklearn.decomposition import PCA

X = np.array([[-1, -1, 4, 1], [-2, -1, 4, 2], [-3, -2, 4, 3], [1, 1, 4, 4], [2, 1, 4, 5], [3, 2, 4, 6]])
pca = PCA(n_components=0.95, whiten=True, svd_solver='full').fit(X)
pca.components_
array([[ 0.71417303,  0.46711713,  0.        ,  0.52130459],
       [-0.46602418, -0.23839061, -0.        ,  0.85205128]])
np.sum(np.abs(pca.components_), axis=0)
array([1.18019721, 0.70550774, 0.        , 1.37335586])

在我看来,这可以衡量每个原始特征的重要性。请注意,第三个特征的重要性为零,因为我有意创建了一个只是常量值的列。

是否有更好的 PCA“重要性度量”?

PCA 的重要性度量在 explained_variance_ratio_ 中。此数组提供每个组件解释的方差百分比。它按组件的重要性降序排列,当所有组件都被使用时总和为 1,或者超过请求阈值的最小可能值。在您的示例中,您将阈值设置为 95%(应解释的方差),因此数组总和将为 0.9949522861608583,因为第一个组件解释了 92.021143% 和第二个 7.474085% 的方差,因此您收到了 2 个组件。

components_是存储特征space中最大方差方向的数组。它的尺寸是 n_components_n_features_。这是您在应用 transform() 以获得数据的降维投影时乘以数据点的值。

更新

为了获得原始特征对每个主成分的贡献百分比,您只需要归一化components_,因为它们设置了原始向量对投影的贡献量。

r = np.abs(pca.components_.T)
r/r.sum(axis=0)

array([[0.41946155, 0.29941172],
       [0.27435603, 0.15316146],
       [0.        , 0.        ],
       [0.30618242, 0.54742682]])

如您所见,第三个功能对 PC 没有贡献。

如果您需要原始特征对解释方差的总贡献,则需要考虑每个 PC 贡献(即 explained_variance_ratio_):

ev = np.abs(pca.components_.T).dot(pca.explained_variance_ratio_)
ttl_ev = pca.explained_variance_ratio_.sum()*ev/ev.sum()
print(ttl_ev)

[0.40908847 0.26463667 0.         0.32122715]

如果您只是将 PC 与 np.sum(np.abs(pca.components_), axis=0) 相加,即假定所有 PC 都同等重要,但这种情况很少见。要使用 PCA 进行粗略的特征选择,在根据相对贡献缩放 PC 后丢弃低贡献 PC 后求和 and/or。

这是一个直观示例,突出显示了为什么普通总和无法按预期工作。

给定 20 个特征的 3 个观察值(可视化为三个 5x4 热图):

>>> print(X.T)
[[2 1 1 1 1 1 1 1 1 4 1 1 1 4 1 1 1 1 1 2]
 [1 1 1 1 1 1 1 1 1 4 1 1 1 6 3 1 1 1 1 2]
 [1 1 1 2 1 1 1 1 1 5 2 1 1 5 1 1 1 1 1 2]]

这些是生成的 PC:

>>> pca = PCA(n_components=None, whiten=True, svd_solver='full').fit(X.T)

请注意,PC3 在 (2,1) 处具有很高的震级,但如果我们检查其解释的方差,它提供 ~0 贡献:

>>> print(pca.explained_variance_ratio_)
array([0.6638886943392722, 0.3361113056607279, 2.2971091700327738e-32])

这会导致在对未缩放的 PC 求和(左)与对按解释的方差比缩放的 PC 求和(右)时出现特征选择差异:

>>> unscaled = np.sum(np.abs(pca.components_), axis=0)
>>> scaled = np.sum(pca.explained_variance_ratio_[:, None] * np.abs(pca.components_), axis=0)

加上未缩放的总和(左),无意义的PC3仍然被赋予了33%的权重。这导致 (2,1) 被认为是最重要的特征,但如果我们回顾原始数据,(2,1) 对观察结果的区分度很低。

通过缩放和(右),PC1 和 PC2 分别具有 66% 和 33% 的权重。现在 (3,1)(3,2) 是实际跟踪原始数据的最重要的特征。