通过李航的《统计学习方法》(我愿称之为最强),可以很清晰地知道PCA的证明和各个参数的的定义。
pca主成分求解的过程是:
- 将数据进行标准化处理(均值为0,方差为1(可选))
- 求原样本中n个特征的协方差矩阵
- 对协方差矩阵进行特征值分解,并将特征向量组成的矩阵按照对应特征值的大小顺序进行排序,前 k 个特征向量即为前k个主成分。
所以我们完全可以根据定义去求解pca,在《机器学习实战》上有详细的代码:
'''
Created on Jun 1, 2011
@author: Peter Harrington
'''
from numpy import *
def loadDataSet(fileName, delim='\t'):
fr = open(fileName)
stringArr = [line.strip().split(delim) for line in fr.readlines()]
datArr = [list(map(float, line)) for line in stringArr]
dataMat = mat(datArr)
return dataMat
def pca(dataMat, topNfeat=9999999):
meanVal = mean(dataMat, axis=0)
meanRemoved = dataMat - meanVal
covMat = cov(meanRemoved, rowvar=False)
eigVals, eigVects = linalg.eig(covMat)
eigValInd = argsort(eigVals)
eigValInd = eigValInd[:-(topNfeat + 1):-1]
redEigVects = eigVects[:, eigValInd]
lowDData = meanRemoved * redEigVects
reconMat = (lowDData * redEigVects.T) + meanVal
return lowDData, reconMat
dataMat = loadDataSet('testSet.txt')
lowDMat, reconMat = pca(dataMat, 2)
print(f"lowDMat: {lowDMat}")
print(f"reconmat: {reconMat}")
然后再介绍sklearn.decomposition 中的PCA类。 个人觉得非常方便
from sklearn.decomposition import PCA
dataMat = loadData(filename)
pca = PCA(n_components = 2)
transformdData = pca.fit_transform(dataMat)
然后我使用两个算法求解同一组数据的主成分,发现我们手写的算法求出来的主成分(即redEigVects)和sklearn中求出来的(pca.components_)不一样,而且很有规律,求出来的两个东西恰好是转置关系。
然后再去翻书(统计学习方法),这里再夸一下这本书 (/dog),书中介绍了一种除定义之外的求解方法,使用SVD分解求解。 具体的求解方法我就不在这里贴了(大家可以自行翻阅),在书中写得非常好。 具体的步骤就是:
- 构造一个新的矩阵
X
′
=
1
n
?
1
X
X^{'} = \frac{1}{\sqrt{n - 1}} X
X′=n?1
?1?X
- 然后对这个新的矩阵进行SVD分解,
X
′
=
U
Σ
V
T
X^{'} = U\Sigma V^{T}
X′=UΣVT
- 这里的V就是我们要求的定义中的特征向量构成的排序好的matrix
在这里再介绍另一个非常方便的函数np.linalg.svd(X) 这个方法可以非常方便帮助我们求解矩阵的SVD分解
U
,
Σ
,
V
T
=
s
v
d
(
X
)
U, \Sigma , V^{T} = svd(X)
U,Σ,VT=svd(X) 这里一定要记住是
V
T
V^{T}
VT 而不是V 然后再放上sklearn中的源码片段
U, S, V = linalg.svd(X, full_matrices=False)
self.components_ = components_[:n_components]
然后就能找到原因了,我们拿到的其实是
V
T
V^{T}
VT
主成分是
V
T
V^{T}
VT的 row-vector,而我们容易将它错当成columnn-vector
|