一.介绍
主成分分析技术,又称主分量分析技术,旨在利用降维的思想,把多指标转化为少数几个综合指标.
在统计学中,主成分分析PCA是一种简化数据集的技术。它是一个线性变换。这个变换把数据变换到一个新的坐标系统中,使得任何数据投影的第一大方差在第一个坐标(称为第一主成分)上,第二大方差在第二个坐标(第二主成分)上,依次类推。主成分分析经常用于减少数据集的维数,同时保持数据集的对方差贡献最大的特征。这是通过保留低阶主成分,忽略高阶主成分做到的。这样低阶成分往往能够保留住数据的最重要方面。但是,这也不是一定的,要视具体应用而定。本文旨在本人学习代码的笔记,原理部分就有些略过了
二.伪代码
-
去除平均值
-
计算协方差矩阵
-
计算协方差矩阵的特征向量
-
将特征值从大到小排序
-
保留最上面的N个特征向量
-
将数据转换到上述N个特征向量构建的新空间中
三
代码如下
import matplotlib
import numpy as np
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet(filename,delim='\t'):
fr = open(filename)
stringArr = [line.strip().split(delim) for line in fr.readlines()]
dataArr = [list(map(float, line)) for line in stringArr]
return np.mat(dataArr)
def PCA(dataMat, topNfeat=9999999):
#去平均值
#axis = 0,那么输出矩阵是1行,[x,x,x.....x,x] x是每一列的平均
meanVals = mean(dataMat, axis=0)
meanRemoved = dataMat - meanVals
#计算协方差矩阵
covMat = cov(meanRemoved, rowvar=0)
#计算协方差矩阵的特征值和特征向量
eigVals,eigVects = linalg.eig(np.mat(covMat))
#从低到高排序
eigValind = np.argsort(eigVals)
#切断多余的尺寸,因为我们取的是前k个
eigValind = eigValind[:-(topNfeat+1):-1]
#重新组织eigVects最大到最小,这样我们可以更好的明显感受到方差百分比
redEigVects = eigVects[:,eigValind]
#将数据转换为新的维度
lowDDataMat = meanRemoved * redEigVects
#重构原始数据
reconMat = (lowDDataMat * redEigVects.T) + meanVals
return lowDDataMat, reconMat
if __name__ == '__main__':
dataMat = loadDataSet('testSet.txt')
lowDDataMat, reconMat = PCA(dataMat, 1)
print('lowDDataMat包含了降维之后的矩阵,这是一个一维矩阵')
print(np.shape(lowDDataMat))
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(dataMat[:, 0].flatten().A[0], dataMat[:, 1].flatten().A[0], marker='^', s=90)
ax.scatter(reconMat[:, 0].flatten().A[0], dataMat[:, 1].flatten().A[0], marker='o', s=50, c='red')
plt.show()
- 小总结
PCA降维之前有必要对数据标准化吗?
在PCA降维前对数据作标准化操作是重要且必要的,如果数据其中某一特征(矩阵的某一列)的数值特别大,那么它在整个误差计算的比重上就很大,那么可以想象在投影到低维空间之后,为了使低秩分解逼近原数据,整个投影会去努力逼近最大的那一个特征,而忽略数值比较小的特征。因为在建模前我们并不知道每个特征的重要性,这很可能导致了大量的信息缺失。
四.实战项目
利用PCA对半导体制造数据降维
1. 引言
半导体工厂制造设备仅能在几年内保持其先进性,设备生命期有限,t在花费又及其宝贵的情况下,如果制造过程中存在瑕疵,我们就必须要尽早发现,以确保宝贵的时间不会花费在缺陷产品的生产上。
因此我们会考察厂家所提供的数据集,运用机器学习知识进一步减少生产中的错误,为厂家节省大量资金。但是它也比前面使用的数据集更大。准确的来说,包含了590个特征,因此我们需要对这些特征进行降维处理
我们也从数据集中发现此数据集包含了很多的缺失值,NaN标识。几乎每个特征下都有NaN,去除不完整的样本不现实了。因此我们需使用平均值来代替缺失值。
2.代码
- 将NaN代替成平均值的函数
def loadDataSet(filename,delim='\t'):
fr = open(filename)
stringArr = [line.strip().split(delim) for line in fr.readlines()]
dataArr = [list(map(float, line)) for line in stringArr]
return np.mat(dataArr)
- 整体
import matplotlib
import numpy as np
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet(filename,delim='\t'):
fr = open(filename)
stringArr = [line.strip().split(delim) for line in fr.readlines()]
dataArr = [list(map(float, line)) for line in stringArr]
return np.mat(dataArr)
def replaceNanWithMean():
datMat = loadDataSet('secom.data',' ') # 解析数据
numFeat = shape(datMat)[1] # 获取特征维度
for i in range(numFeat):
meanVal = mean(datMat[nonzero(~isnan(datMat[:,i].A))[0],i]) # 利用该维度所有非NaN特征求取均值
datMat[nonzero(isnan(datMat[:,i].A))[0],i] = meanVal # 将该维度中所有NaN特征全部用均值替换
return datMat
if __name__ == '__main__':
dataMat = replaceNanWithMean()
meanVals = mean(dataMat, axis=0)
meanRemoved = dataMat - meanVals
covMat = cov(meanRemoved, rowvar=0)
eigVals, eigVects = linalg.eig(mat(covMat))
print(eigVals)
print('计算90%的主成分方差总和')
print(sum(eigVals)*0.9)
print('计算前6个主成分所占的方差')
print(sum(eigVals[:6]))
print('对前20个画图观察')
plt.plot(eigVals[:20])
plt.show()
由上图,我们也就可以很明显的看到。前六个主成分覆盖率数据96.8%的方差,前二十个主成分覆盖率数据99.3%的方差.因此保留前六个去除后584个主成分,我们就大概可以实现100:1的压缩比。