我正在使用这里的输入数据(参见第 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 ]]
令人惊讶的是,预测与上述数据源的结果相匹配。
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]])
这是我不明白的:
- 为什么协方差矩阵不同?
- 更新:如何从 scikit-learn 获取尚未归一化的特征值?
此数据的正确协方差矩阵:
numpy.cov(data.transpose())
array([[ 0.61655556, 0.61544444], [ 0.61544444, 0.71655556]])
有偏差(即"不正确",使用错误的归一化项,并低估数据集中的方差)协方差矩阵:
numpy.cov(data.transpose(), bias=1)
array([[ 0.5549, 0.5539], [ 0.5539, 0.6449]])
Numpy知道您必须将数据居中 - 因此您不需要centered_data
。
PCA 分量不是 1:1 的特征值。
正确的特征值分解:
numpy.linalg.eig(numpy.cov(data.transpose()))
(array([ 0.0490834 , 1.28402771]), array([[-0.73517866, -0.6778734 ], [ 0.6778734 , -0.73517866]]))
使用有偏差估计量会产生不同的特征值(再次低估方差),但相同的特征向量:
(array([ 0.04417506, 1.15562494]), ...
请注意,特征向量尚未按最大特征值排序。
正如pca.explained_variance_ratio_
的名称所示,这些不是特征值。他们就是比例。如果我们取(有偏见的、低估的)特征值,并将它们归一化为总和 1,我们得到
s/sum(s)
array([ 0.03681869, 0.96318131])
此外,scipy的pca.transform
方法显然不应用缩放。恕我直言,在使用 PCA 时,缩放每个组件以具有单位方差也是相当常见的。这显然不适用于此输出。然后结果将是(交换两列,我没有费心更改它)
s, e = numpy.linalg.eig(numpy.cov(data.transpose()))
o=numpy.argsort(s)[::-1]
(data-mean).dot(e[:,o]) / numpy.sqrt(s[o])
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]])
(如您所见,PCA 在numpy
中只有三行,因此您不需要函数。
为什么我认为这是正确的结果?因为生成的数据集具有这样的属性,即它的协方差矩阵是(舍入误差除外)单位矩阵。如果不进行缩放,则协方差矩阵numpy.diag(s[o])
。但有人可能会争辩说,通过应用缩放,我"丢失"了方差信息,否则这些信息本来会保留。
在我看来,scipy
使用了错误的(有偏见的)协方差。 numpy
是正确的。
但通常情况下,这并不重要。在上述比率中,偏差被抵消。如果你有一个大型数据集,那么使用朴素1/n
和无偏见1/(n-1)
之间的差异最终会变得微不足道。但差异实际上也来自零 CPU 成本,因此您不妨使用无偏方差估计。
(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。