Python 中的 Sparse PCA 实现有什么作用?

机器算法验证 Python 主成分分析 scikit-学习 降维
2022-03-19 23:28:39

我对在 python 中使用稀疏 PCA 很感兴趣,我找到了 sklearn 实现。但是,我认为这个 python 实现解决了与本文提出并在 R 包elasticnet中实现的原始稀疏 pca 算法不同的问题例如,考虑以下关于稀疏 PC 的解释方差的示例:

import numpy as np
from sklearn.datasets import load_boston
boston = load_boston()
from sklearn.decomposition import SparsePCA

x = boston.data # Load boston dataset
x = x[:, [0, 2, 4, 5, 6, 7, 10, 11, 12]] # select non-categorical variables
spca = SparsePCA(n_components=5, alpha=1e-3, ridge_alpha=1e-6, normalize_components=False) # Solve sparse pca
spca.fit(x)
t_spca = spca.transform(x)
p_spca = spca.components_.T

# Calculate the explained variance as explained in sparse pca original paper

t_spca_qr = np.linalg.qr(t_spca) # QR decomposition of modified PCs

q = t_spca_qr[0]
r = t_spca_qr[1]

# compute adjusted variance
variance = []
for i in range(5):
    variance.append(np.square(r[i][i]))

variance = np.array(variance)

# compute variance_ratio
total_variance_in_x = np.matrix.trace(np.cov(x.T)) # Variance in the original dataset
explained_variance_ratio = np.cumsum(variance / total_variance_in_x)

array([ 0.00010743,  0.00021485,  0.00032228,  0.0004297 ,  0.00053713])

使用稀疏 PCA 的解释方差计算基于上面引用的原始论文,第 273 页。因此,如您所见,这个解释方差比非常小。

我的问题是:

  1. 我在解释方差的计算上做错了吗?
  2. 有没有什么地方可以找到用 python 实现的稀疏 pca 的数学公式?
  3. spca python实现中的normalize_components参数有什么作用?为什么设置为时会引发弃用警告False

编辑(基于答案)

根据答案,我通过设置normalize_components=True和避免这种方式的弃用警告来测试结果。

spca = SparsePCA(n_components=5, alpha=1e-3, ridge_alpha=1e-6, normalize_components=True) # Solve sparse pca
spca.fit(x)
t_spca = spca.transform(x)
p_spca = spca.components_.T
t_spca_qr = np.linalg.qr(t_spca) 
r = t_spca_qr[1]
# compute adjusted variance
variance = []
for i in range(5):
    variance.append(np.square(r[i][i]))
variance = np.array(variance)

这会产生以下结果variance

variance
array([ 4255042.12587337,   386089.3106474 ,    31883.68815345, 15333.57500443,     9781.36298748])

但是,这些数字远大于样本大小n=505或原始矩阵 x 的方差,total_variance_in_x=9308.784因此通过将方差数组的条目除以 505 或 9308.784,我仍然没有得到关于解释方差的有意义的结果。

1个回答

回答:

  1. 您的代码似乎与引用的论文一致,并且不一致是scikit-learn版本 <中使用的主要组件的非标准定义的人工制品0.22(这在弃用消息中提到)。

    您可以通过以下方式获得有意义的结果

    • 环境normalize_components=True
    • 将数组的条目除以variance样本数,505。

    这为您提供了解释的方差比,例如

    0.90514782, 0.98727812, 0.99406053, 0.99732234, 0.99940307.

  2. 3. 最直接的方法是查看sklearn.decomposition计算机上的源文件。


细节:

  • 的代码SparsePCA,如scikit-learn=0.21.3,有一个意想不到的伪像: as is 返回输入的转换,使得分解的对角线中具有非零值(在逗号后四舍五入到 5 位,易于检查),因此不能反映 Zou、Hastie 和 Tibshirani 所认为的保留方差。QRR {1,1}

  • normalize components是获得有意义的方差比的关键。这个论点只存在于scikit-learn=0.21.3和不存在于 中scikit-learn=0.22设置为False它会导致输出的归一化,隐藏有关解释方差的信息。可以在源代码中看到这种规范化的细节:

class SparsePCA(BaseEstimator,TransformerMixin):

  ...

  def transform(self, X):

     ...

     U = ridge_regression(...)

     if not self.normalize_components:
         s = np.sqrt((U ** 2).sum(axis=0))
         s[s == 0] = 1
         U /= s

     return U

弃用警告显示此规范化不符合主成分的通用定义,并已在 version中删除0.22

如果您仍在使用像我这样的旧版本,则可以按照答案的简短版本中所述反转这种规范化。