Scikit-Learn PCA

sla*_*law 13 pca scikit-learn

我正在使用此处的输入数据(参见第3.1节).

我试图使用scikit-learn重现它们的协方差矩阵,特征值和特征向量.但是,我无法重现数据源中显示的结果.我也在其他地方看过这个输入数据,但是我无法辨别它是scikit-learn,我的步骤还是数据源的问题.

data = np.array([[2.5,2.4],
                 [0.5,0.7],
                 [2.2,2.9],
                 [1.9,2.2],
                 [3.1,3.0],
                 [2.3,2.7],
                 [2.0,1.6],
                 [1.0,1.1],
                 [1.5,1.6],
                 [1.1,0.9],
                 ]) 

centered_data = data-data.mean(axis=0)
pca = PCA()
pca.fit(centered_data)
print(pca.get_covariance()) #Covariance Matrix

array([[ 0.5549,  0.5539],
   [ 0.5539,  0.6449]])

print(pca.explained_variance_ratio_) #Eigenvalues (normalized)

[ 0.96318131  0.03681869]

print(pca.components_) #Eigenvectors

[[-0.6778734  -0.73517866]
 [ 0.73517866 -0.6778734 ]]
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,投影与来自上述数据源的结果相匹配.

print(pca.transform(centered_data)) #Projections

array([[-0.82797019,  0.17511531],
   [ 1.77758033, -0.14285723],
   [-0.99219749, -0.38437499],
   [-0.27421042, -0.13041721],
   [-1.67580142,  0.20949846],
   [-0.9129491 , -0.17528244],
   [ 0.09910944,  0.3498247 ],
   [ 1.14457216, -0.04641726],
   [ 0.43804614, -0.01776463],
   [ 1.22382056,  0.16267529]])
Run Code Online (Sandbox Code Playgroud)

这是我不明白的:

  1. 为什么协方差矩阵不同?
  2. 更新:如何从scikit-learn获取尚未标准化的特征值?

Ano*_*sse 15

纠正此数据的协方差矩阵:

numpy.cov(data.transpose())
Run Code Online (Sandbox Code Playgroud)
array([[ 0.61655556,  0.61544444],
       [ 0.61544444,  0.71655556]])
Run Code Online (Sandbox Code Playgroud)

偏差(即"不正确",使用错误的归一化项,并低估数据集中的方差)协方差矩阵:

numpy.cov(data.transpose(), bias=1)
Run Code Online (Sandbox Code Playgroud)
array([[ 0.5549,  0.5539],
       [ 0.5539,  0.6449]])
Run Code Online (Sandbox Code Playgroud)

Numpy知道你必须集中数据 - 所以你不需要centered_data.

PCA组件的特征值不是 1:1.

正确的特征值分解:

numpy.linalg.eig(numpy.cov(data.transpose()))
Run Code Online (Sandbox Code Playgroud)
(array([ 0.0490834 ,  1.28402771]),
 array([[-0.73517866, -0.6778734 ],
        [ 0.6778734 , -0.73517866]]))
Run Code Online (Sandbox Code Playgroud)

使用偏置估计器会产生不同的特征值(同样,低估方差),但相同的特征向量:

(array([ 0.04417506,  1.15562494]), ...
Run Code Online (Sandbox Code Playgroud)

请注意,特征向量尚未按最大特征值排序.

作为pca.explained_variance_ratio_指示的名称,这些不是特征值.他们是比例.如果我们采用(有偏见的,低估的)特征值,并将它们归一化为1,我们得到

s/sum(s)
Run Code Online (Sandbox Code Playgroud)
array([ 0.03681869,  0.96318131])
Run Code Online (Sandbox Code Playgroud)

此外,pca.transformSciPy的方法显然并不能适用缩放.恕我直言,当使用PCA时,将每个组件缩放以具有单位方差也是相当普遍的.这显然不适用于此输出.然后结果将是(交换两列,我没有打扰改变这个)

s, e = numpy.linalg.eig(numpy.cov(data.transpose()))
o=numpy.argsort(s)[::-1]
(data-mean).dot(e[:,o]) / numpy.sqrt(s[o])
Run Code Online (Sandbox Code Playgroud)
array([[-0.73068047, -0.79041795],
       [ 1.56870773,  0.64481466],
       [-0.87561043,  1.73495337],
       [-0.24198963,  0.58866414],
       [-1.47888824, -0.94561319],
       [-0.80567404,  0.79117236],
       [ 0.08746369, -1.57900372],
       [ 1.01008049,  0.20951358],
       [ 0.38657401,  0.08018421],
       [ 1.08001688, -0.73426743]])
Run Code Online (Sandbox Code Playgroud)

(正如你所看到的,PCA只有三行numpy,所以你不需要这个功能.)

为什么我认为这是正确的结果?因为所得到的数据集具有它的协方差矩阵是(除了舍入误差)的属性同一性矩阵.没有缩放,协方差矩阵是numpy.diag(s[o]).但也有人可能会争辩说,通过应用缩放,我"丢失"了本来会保留的方差信息.

在我看来,scipy使用错误的(有偏见的)协方差.numpy是正确的.

但通常情况下,这并不重要.在上述比率中,偏差抵消了.如果你有一个大的数据集,那么使用天真1/n和无偏见之间的区别1/(n-1)最终会变得无法实现.但是,差异在于实际上零CPU成本,因此您也可以使用无偏差方差估计.


Lor*_*ton 1

(1) 的简短答案是,当您将 PCA 应用于贬低的数据时,您已经旋转了它,并且新的向量空间表示具有不同协方差的新随机变量。(2) 的答案是,如果您想要非标准化特征值,只需对数据的协方差矩阵进行特征分解即可。

更多信息:

使用 scipy 计算特征值:http://docs.scipy.org/doc/numpy/reference/ generated/numpy.linalg.eigvals.html

您可以计算数据矩阵的 SVD(不是协方差)并查看奇异值: http://docs.scipy.org/doc/numpy/reference/ generated/numpy.linalg.svd.html

显然,scikit-learn 有不同风格的 SVD,您可能想尝试一下。