目录
一、核心思想与目标
主成分分析(Principal Component Analysis, PCA)是一种无监督学习的降维算法,核心思想是通过线性变换将原始高维数据映射到低维空间,同时尽可能保留数据的主要方差(即信息)。
目标:
- 降低数据维度,简化计算复杂度。
- 去除数据中的冗余信息(相关性),提取最具代表性的 “主成分”。
二、数学原理与推导
假设原始数据为 n 维随机变量 X=(X1,X2,…,Xn)的T次方,需将其降至 k 维(k<n)。
2.1 关键概念
-
主成分:原始变量的线性组合,彼此正交(不相关),且按方差从大到小排序。
第 i 个主成分 Yi 表示为:
其中 ai 是单位向量(∥ai∥=1),称为主成分载荷向量。 -
方差与协方差:主成分的方差越大,携带的信息越多。 PCA 通过最大化方差来筛选主成分。
原始数据的协方差矩阵为,其中 μ 是均值向量。
2.2 推导步骤
-
数据标准化:
对原始数据进行均值归一化和方差归一化,使各变量均值为 0,方差为 1,避免量纲影响。标准化后的数据协方差矩阵等于相关系数矩阵。
-
计算协方差矩阵:
设标准化后的数据矩阵为(m 个样本,n 个特征),协方差矩阵为:
-
特征值分解或奇异值分解(SVD):
- 特征值分解:对协方差矩阵 Σ 进行分解,得到特征值 λ1≥λ2≥⋯≥λn≥0 和对应的特征向量 v1,v2,…,vn。
特征向量构成正交矩阵 V=[v1,v2,…,vn],主成分载荷向量即前 k 个特征向量。 - 奇异值分解(更高效):对标准化数据矩阵 X 直接进行 SVD:
。
其中 V 的列向量即为协方差矩阵的特征向量,奇异值 σi 与特征值 λi 的关系为。
- 特征值分解:对协方差矩阵 Σ 进行分解,得到特征值 λ1≥λ2≥⋯≥λn≥0 和对应的特征向量 v1,v2,…,vn。
-
选择主成分数量 k:
根据累计方差贡献率确定 k,即前 k 个特征值之和占总特征值之和的比例:累计方差贡献率=∑i=1nλi∑i=1kλi×100%
通常取贡献率达 80%~95% 的最小 k 值。 -
映射数据到低维空间:
原始数据 X 通过前 k 个特征向量投影到低维空间,得到主成分矩阵 Y:Y=XVk
其中 Vk=[v1,v2,…,vk] 是前 k 个特征向量组成的矩阵。
三、利用PCA进行人脸识别
1.数据准备
本次实验的数据集ORL-Faces包含40个人,每人拥有10张正脸照片,取每个人的7张照片,作为训练数据。那么每个人剩下的3张照片,计算机还没有看过,就可以在计算机认识了每一个人之后用来考验计算机是否真的能够正确识别图像中的人是谁。
2.创建每个训练样本组成的M*N矩阵
bigList = []
# 导入人脸模型库
faceCascade = cv2.CascadeClassifier(r'C:\Python\haarshare\haarcascade_frontalface_alt.xml')
# 遍历30个人
for i in range(1, 31):
# 遍历每个人的7张照片
for j in range(1, 8):
list = []
# 直接读入灰度照片
image = cv2.imread("C:\\Users\\tangyitao\\Pictures\\Saved Pictures\\trainFace\\train"
+ str(i) + "\\train" + str(i) + "" + str(j) + ".jpg", 0)
faces = faceCascade.detectMultiScale(image, 1.3, 5)
for (x, y, w, h) in faces:
# 裁剪人脸区域为 128 * 128 大小
cutResize = cv2.resize(image[y:y + h, x:x + w], (128, 128),
interpolation=cv2.INTER_CUBIC)
# 遍历图片行数
for x in range(cutResize.shape[0]):
# 遍历图片每一行的每一列
for y in range(cutResize.shape[1]):
# 将每一处的灰度值添加至列表
list.append(cutResize[x, y])
bigList.append(list)
print("\n\ntrainFaceMat ")
trainFaceMat = numpy.mat(bigList) # 得到训练样本矩阵
print("trainFaceMat.shape[0] ",trainFaceMat.shape[0])
print("trainFaceMat.shape[1]",trainFaceMat.shape[1])
print(trainFaceMat)
3.得到规格化的训练样本数据
meanFaceMat = numpy.mean(trainFaceMat, axis=0) # 每一列的和除行数,得到平均值
print("meanFaceMat \n\n")
print("meanFaceMat.shape[0] ",meanFaceMat.shape[0])
print("meanFaceMat.shape[1] ",meanFaceMat.shape[1])
print(meanFaceMat)
normTrainFaceMat = trainFaceMat - meanFaceMat
print("\n\n normTrainFaceMat")
print("normTrainFaceMat.shape[0] ",normTrainFaceMat.shape[0])
print("normTrainFaceMat.shape[1] ",normTrainFaceMat.shape[1])
print(normTrainFaceMat)
4.计算协方差矩阵并求的特征值和特征向量
covariance = numpy.cov(normTrainFaceMat)
# 求得协方差矩阵的特征值和特征向量
eigenvalue, featurevector = numpy.linalg.eig(covariance)
5.对特征值进行排序并保留k个最大特征值的特征向量
sorted_Index = numpy.argsort(eigenvalue)
topk_evecs = featurevector[:,sorted_Index[:-140-1:-1]]
6.计算投影
7.创建测试样本矩阵
# 主要思想和第一步计算trainFaceMat差不多,这里只需要添加一张照片的数据
list = []
faceCascade = cv2.CascadeClassifier(r'C:\Python\haarshare\haarcascade_frontalface_alt.xml')
# fileName 为待识别图片的文件名,读入灰度人脸
image = cv2.imread(fileName, 0)
faces = self.faceCascade.detectMultiScale(self.image, 1.3, 5)
for (x, y, w, h) in self.faces:
cut = image[y:y + h, x:x + w]
# 处理成 128 * 128大小的人脸
cutResize = cv2.resize(cut, (128, 128), interpolation=cv2.INTER_CUBIC)
for x in range(cutResize.shape[0]):
for y in range(cutResize.shape[1]):
list.append(cutResize[x, y])
testFaceMat = numpy.mat(list)
8.进行规格化
normTestFaceMat = testFaceMat - meanFaceMat
9.计算欧式距离找到匹配人脸
eigen_test_sample = numpy.dot(normTestFaceMat, eigenface)
# 以 eigen_train_sample[0]与eigen_test_sample的欧式距离赋值 minDistance
minDistance = numpy.linalg.norm(eigen_train_sample[0] - eigen_test_sample)
# num 记录训练集中第几个人与待识别人为同一人
num = 1
# 遍历 eigen_train_sample 的每一行,在此处,eigen_train_sample.shape[0] = 210。
for i in range(1, eigen_train_sample.shape[0]):
distance = numpy.linalg.norm(eigen_train_sample[i] - eigen_test_sample)
if minDistance > distance:
minDistance = distance
# 30个人中,每个人有7张照片,i是记录的第几张照片
# 因此记录第几个人的num为 i // 7 + 1。
num = i // 7 + 1
四、总结
PCA作为机器学习中经典的线性降维算法,通过”最小重构误差“为目标导向对数据进行投影实现降维,如今仍然在机器学习许多领域(语言图像处理、数据可视化)有优异表现。它在降低数据复杂性,降低运算量上有显著优势。但作为一种无监督学习方法(对训练样本没有做标注),在对数据完全无知的情况下,PCA并不能得到较好的保留数据信息并且有可能损失重要信息,且PCA对于主成分的分析判断是影响实验结果的重要因素,另外,PCA对于非线性的数据降维效果较差,我们在进行非线性数据降维时最好采用其它方法。