scikit-learn PCA:矩阵变换产生具有翻转符号的PC估计

时间:2014-01-14 14:12:09

标签: python scikit-learn pca

我正在使用scikit-learn在this dataset上执行PCA。 scikit-learn文档states that

  

由于奇异值分解的实现微妙   (SVD),在这个实现中使用,运行适合两次   相同的矩阵可以导致主要组件翻转标志   (改变方向)。因此,始终使用非常重要   相同的估算器对象以一致的方式转换数据。

问题是我不认为我使用不同的估算器对象,但与SAS PROC PRINCOMP程序的结果相比,我的某些PC的迹象被翻转。

对于数据集中的第一次观察,SAS PC是:

PC1      PC2      PC3       PC4      PC5
2.0508   1.9600   -0.1663   0.2965   -0.0121

从scikit-learn,我得到以下(其数量非常接近):

PC1      PC2      PC3       PC4      PC5
-2.0536  -1.9627  -0.1666   -0.297   -0.0122

这就是我正在做的事情:

import pandas as pd
import numpy  as np
from sklearn.decomposition.pca import PCA

sourcef = pd.read_csv('C:/mydata.csv')
frame = pd.DataFrame(sourcef)

# Some pandas evals, regressions, etc... that I'm not showing
# but not affecting the matrix

# Make sure we are working with the proper data -- drop the response variable
cols = [col for col in frame.columns if col not in ['response']]

# Separate out the data matrix from the response variable vector 
# into numpy arrays
frame2_X = frame[cols].values
frame2_y = frame['response'].values

# Standardize the values
X_means = np.mean(frame2_X,axis=0)
X_stds  = np.std(frame2_X,axis=0)

y_mean = np.mean(frame2_y)
y_std  = np.std(frame2_y)

frame2_X_stdz = np.copy(frame2_X)
frame2_y_stdz = frame2_y.astype(numpy.float32, copy=True)

for (x,y), value in np.ndenumerate(frame2_X_stdz):
    frame2_X_stdz[x][y] = (value - X_means[y])/X_stds[y]

for index, value in enumerate(frame2_y_stdz):
    frame2_y_stdz[index] = (float(value) - y_mean)/y_std

# Show the first 5 elements of the standardized values, to verify
print frame2_X_stdz[:,0][:5]

# Show the first 5 lines from the standardized response vector, to verify
print frame2_y_stdz[:5]

那些退房确定:

[ 0.9508 -0.5847 -0.2797 -0.4039 -0.598 ]
[ 1.0726 -0.5009 -0.0942 -0.1187 -0.8043]

继续......

# Create a PCA object
pca = PCA()
pca.fit(frame2_X_stdz)

# Create the matrix of PC estimates
pca.transform(frame2_X_stdz)

这是最后一步的输出:

Out[16]: array([[-2.0536, -1.9627, -0.1666, -0.297 , -0.0122],
       [ 1.382 , -0.382 , -0.5692, -0.0257, -0.0509],
       [ 0.4342,  0.611 ,  0.2701,  0.062 , -0.011 ],
       ..., 
       [ 0.0422,  0.7251, -0.1926,  0.0089,  0.0005],
       [ 1.4502, -0.7115, -0.0733,  0.0013, -0.0557],
       [ 0.258 ,  0.3684,  0.1873,  0.0403,  0.0042]])

我已经尝试将pca.fit()pca.transform()替换为pca.fit_transform(),但我的结果却相同。

我在这里犯了什么错误,我正在拿着标牌翻转的电脑?

2 个答案:

答案 0 :(得分:5)

你没有做错任何事。

文档警告你的是,对fit的重复调用可能产生不同的主要组件 - 而不是它们与另一个PCA实现的关系。

在所有组件上都有翻转符号不会使结果错误 - 只要符合定义,结果就是正确的(选择每个组件以便捕获最大差异量)在数据中)。就目前而言,您所获得的投影似乎只是镜像 - 它仍然符合定义,因此是正确的。

如果在正确性之下,你担心实现之间的一致性,你可以在必要时简单地将组件乘以-1。

答案 1 :(得分:0)

不保证SVD分解是唯一的 - 只有值是相同的,因为svd()的不同实现可以产生不同的符号。任何特征向量都可以有翻转符号,并且在转换时会产生相同的结果,然后转换回原始空间。 sklearn中使用SVD分解的大多数算法使用函数sklearn.utils.extmath.svd_flip()来纠正这个问题,并在算法之间强制执行相同的约定。由于历史原因,PCA()从来没有得到过这个修复(尽管它应该......)

一般来说,这不是一件值得担心的事情 - 只是通常实施的SVD算法的限制。

另外需要注意的是,我发现将PC权重(以及一般参数权重)的重要性分配给了危险,因为这些问题正好存在。数值/实现细节不应该影响您的分析结果,但很多时候很难说出数据的结果是什么,以及您用于探索的算法的结果是什么。我知道这是一项家庭作业,不是一种选择,但重要的是记住这些事情!

相关问题