【发布时间】:2016-10-03 05:51:00
【问题描述】:
当我们发布关于 PCA 的 homework assignment 时,我们告诉课程参与者选择任何计算他们发现的特征向量的方法。他们找到了多种方法:eig、eigh(我们最喜欢的是svd)。在后来的任务中,我们告诉他们使用 scikit-learn 的 PCA - 结果与我们预期的相差很大。
我玩弄了一下,我们向参与者发布了一个解释,即两种解决方案都是正确的,并且可能只是算法中的数值不稳定。然而,最近我在与一位同事的讨论中再次选择了该文件,我们很快发现有一个有趣的微妙变化可以使所有结果几乎相等:转置从 SVD 获得的特征向量(因此从PCA)。
一些代码来显示这个:
def pca_eig(data):
"""Uses numpy.linalg.eig to calculate the PCA."""
data = data.T @ data
val, vec = np.linalg.eig(data)
return val, vec
对
def pca_svd(data):
"""Uses numpy.linalg.svd to calculate the PCA."""
u, s, v = np.linalg.svd(data)
return s ** 2, v
不会产生相同的结果。但是,将 pca_svd 的返回值更改为 s ** 2, v.T 有效!遵循wikipedia 的定义非常有意义:X 的 SVD 遵循 X=UΣWT where
X的右奇异向量W等价于X的特征向量TX
所以为了得到特征向量,我们需要转置输出v 的np.linalg.eig(...)。
除非有其他事情发生?无论如何,PCA 和IncrementalPCA 都显示错误的结果(或者eig 是错误的?我的意思是,转置产生相同的相等性),并且查看the code for PCA 表明他们正在这样做,就像我最初所做的那样:
U, S, V = linalg.svd(X, full_matrices=False)
# flip eigenvectors' sign to enforce deterministic output
U, V = svd_flip(U, V)
components_ = V
我创建了一个小 gist 来展示差异 (nbviewer),第一个使用 PCA 和 IncPCA(也没有 SVD 的转置),第二个使用转置的特征向量:
没有转置 SVD/PCA 的比较(标准化数据)
与 SVD/PCA 转置的比较(标准化数据)
可以清楚地看到,上图的结果并不是很好,而下图只是在一些符号上有所不同,因此到处反映了结果。
这真的是错误的还是 scikit-learn 中的错误?我更有可能使用错误的数学 - 但什么是正确的?你能帮帮我吗?
【问题讨论】:
标签: scikit-learn pca