赞
踩
PCA(principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据压缩算法
事实上,通过计算数据矩阵的协方差矩阵,然后得到协方差矩阵的特征值及特征向量,选择特征值最大(也即包含方差最大)的N个特征所对应的特征向量组成的矩阵 → \rightarrow →就可以将数据矩阵转换到新的空间当中,实现数据特征的降维(N维)
一种直观的看法是:希望投影后的的投影值尽可能分散
→
\rightarrow
→可以用数学上的方差来表述
V
a
r
(
a
)
=
1
m
∑
i
=
1
m
(
a
i
−
μ
)
2
V_{ar}(a) = \frac 1m \sum_{i=1}^m(a_i-\mu)^2
Var(a)=m1i=1∑m(ai−μ)2
对于上面二维降成一维的问题来说,找到那个使得方差最大的方向就可以了
对于更高维:例如考虑三维降到二维问题
考虑下图中的大量数据点。如果要求我们画出一条直线,这条线要尽可能覆盖这些点,那么最长的线可能是哪条?
3条直线中B最长。在PCA中,我们对数据的坐标进行了旋转,该旋转的过程取决于数据的本身。第一条坐标轴旋转到覆盖数据的最大方差位置,即图中的直线B。数据的最大方差给出了数据的最重要的信息。假如该坐标轴与第一条坐标轴垂直,它就是覆盖数据次大差异性的坐标轴。这里更严谨的说法就是正交(orthogonal) ,直线C就是第二条坐标轴。
PCA的基本过程:
伪代码
去除平均值
计算协方差矩阵
计算协方差矩阵的特征值和特征向量
将特征值从大到小排序
保留最上面的N个特征向量
将数据转换到上述N个特征向量构建的新空间中
python代码
def pca(dataMat, topNfeat=9999999): meanVals = np.mean(dataMat, axis=0) # 计算平均值 meanRemoved = dataMat - meanVals # 去中心化 covMat = np.cov(meanRemoved, rowvar=False) # 计算协方差矩阵 eigVals, eigVects = np.linalg.eig(np.mat(covMat)) # 得到所有的特征值eigVals和特征向量eigVects sum_eig = sum(eigVals) percentVar = eigVals / sum_eig cumVarPercent = 0.0 print('自编python代码:') for i in range(topNfeat): cumVarPercent += percentVar[i] print("第%d个主成分所占的方差百分比:%f,累计方差百分比:%f" % (i + 1, percentVar[i], cumVarPercent)) plt.plot(range(30), percentVar[:30]) # 绘图 x_major_locator = MultipleLocator(1) # 把x轴的刻度间隔设置为1,并存在变量里 ax = plt.gca() # ax为两条坐标轴的实例 ax.xaxis.set_major_locator(x_major_locator) # 把x轴的主刻度设置为1的倍数 plt.xlim(-0.5, 30) plt.rcParams['font.sans-serif'] = ['SimHei'] plt.xlabel("主成分数目") plt.ylabel("方差百分比") plt.title('不同主成分下的方差百分比') eigValInd = np.argsort(eigVals) # 排序 eigValInd = eigValInd[:-(topNfeat + 1):-1] # 保留至想要的维度 redEigVects = eigVects[:, eigValInd] # 从大到小排列特征向量,得到投影矩阵 lowDataMat = meanRemoved * redEigVects # 投影到新的特征空间后的数据集 reconMat = (lowDataMat * redEigVects.T) + meanVals # 重构矩阵,即得出降维后矩阵在原维度下是什么样的,便于比较 return lowDataMat, reconMat
读取数据:
def loadDataSet(fileName, delim='\t'):
dataArr = pd.read_csv('secom.data', sep=' ', names=[i for i in range(590)]) # 添加列索引,防止把第一列当成列索引
# dataArr = np.array(dataArr)
print(dataArr)
return np.mat(dataArr)
数据包含很多的缺失值NaN (Not a Number) → \rightarrow →用平均值来代替缺失值,平均值根据那些非NAN得到。
def replaceNanWithMean():
dataMat = loadDataSet('secom.data', '')
numFeat = np.shape(dataMat)[1]
for i in range(numFeat):
meanVal = np.mean(dataMat[np.nonzero(~np.isnan(dataMat[:, i].A))[0], i])
dataMat[np.nonzero(np.isnan(dataMat[:, i].A))[0], i] = meanVal
return dataMat
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。