目录
背景
在许多领域的研究与应用中,通常需要对含有多个变量的数据进行观测,收集大量数据后进行分析寻找规律。多变量大数据集无疑会为研究和应用提供丰富的信息,但是也在一定程度上增加了数据采集的工作量。更重要的是在很多情形下,许多变量之间可能存在相关性,从而增加了问题分析的复杂性。如果分别对每个指标进行分析,分析往往是孤立的,不能完全利用数据中的信息,因此盲目减少指标会损失很多有用的信息,从而产生错误的结论。因此需要找到一种合理的方法,在减少需要分析的指标同时,尽量减少原指标包含信息的损失,以达到对所收集数据进行全面分析的目的。由于各变量之间存在一定的相关关系,因此可以考虑将关系紧密的变量变成尽可能少的新变量,使这些新变量是两两不相关的,那么就可以用较少的综合指标分别代表存在于各个变量中的各类信息。主成分分析与因子分析就属于这类降维算法。
引入
PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法(非监督的机器学习方法)。其最主要的用途在于“降维”,通过析取主成分显出的最大的个别差异,发现更便于人类理解的特征。也可以用来削减回归分析和聚类分析中变量的数目。
特征维度约减
特征维度约减的概念
• 特征约减的目的是将高维特征向量映射到低维子空间中.
• 给定n个样本(每个样本维度为p维){x1,x2,……xn}
通过特征变换/投影矩阵实现特征空间的压缩:
为何要维度约减?
•大多数机器学习算法在高维空间中表现不够鲁棒
–Curse of Dimensionality
–查询速度与精度随着维度增加而降低.
•有价值的维度往往很少
–例如,在基因序列中对于特定疾病有价值的点位十分有限.
• 可视化: 高位数据在 2D 或 3D空间中的可视化
• 维度约减: 高效的存储与检索
• 噪声消除: 提升分类或识别精度
维度约减的应用
常规维度约减方法
• 无监督方法
– Latent Semantic Indexing (LSI): truncated SVD
– Independent Component Analysis (ICA)
– Principal Component Analysis (PCA)
– Canonical Correlation Analysis (CCA)
• 监督方法
– Linear Discriminant Analysis (LDA)
• 半监督方法
– Research topic
主成分分析
主成分分析 (PCA)基本思路
–通过协方差分析,建立高维空间到低维空间的线性映射/矩阵
–保留尽可能多的样本信息
–压缩后的数据对分类、聚类尽量不产生影响,甚至有所提升
•将原始高维向量通过投影矩阵,投射到低维空间
–这些向量称为主成分 (PCs), 具有无关性、正交的特点。重要的是这些向量的数量要远小于高维空间的维度。
主成分的代数定义和代数推导
主成分的代数定义
给定n个样本(每个样本维度为p维):
定义为样本在第一主成分/主方向a1上的投影:
其中
我们的目标是找到a1, 使z1的方差最大。
主成分的代数推导
首先根据z1的方差定义,推导得出:
可以看出,S是维度之间的协方差矩阵,是样本均值,在实际计算中,可以先将样本减去均值使得=0。
假设=0,根据样本组成的矩阵:
有协方差矩阵:
可证明S半正定!
目标是找到主方向a1,使得z1的方差 最大化,且满足,令 λ 为一个 Lagrange 乘子,则有:
得出a1是协方差矩阵 S 的特征向量。可验证a1对应的特征值,是S的最大特征值。
在a1的基础上,要计算下一个主成分a2,使得z2方差最大化,则有:
根据协方差定义,有:
分别令 λ 与 φ 为 Lagrange 乘子,问题变成最大化:
实际上可以求证a2也是协方差矩阵 S 的特征向量,且a2是S的第二大的特征向量。
以此类推, 可以验证:
• 协方差矩阵S的第k大特征向量对应数据的第k主成分
• 第k大特征向量对应的特征值,为投影到该主成分的方差
PCA算法两种实现方法
1、基于特征值分解协方差矩阵实现PCA算法
输入:数据集 ,需要降到k维。
1、去平均值(即去中心化),即每一位特征减去各自的平均值。
2、计算协方差矩阵 ,注:这里除或不除样本数量n或n-1,其实对求出的特征向量没有影响。
3、用特征值分解方法求协方差矩阵 的特征值与特征向量。
4、对特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为行向量组成特征向量矩阵P。
5、将数据转换到k个特征向量构建的新空间中,即Y=PX。
2、基于SVD分解协方差矩阵实现PCA算法
输入:数据集 ,需要降到k维。
1、去平均值,即每一位特征减去各自的平均值。
2、计算协方差矩阵。
3、通过SVD计算协方差矩阵的特征值与特征向量。
4、对特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为列向量组成特征向量矩阵。
5、将数据转换到k个特征向量构建的新空间中。
在PCA降维中,我们需要找到样本协方差矩阵 的最大k个特征向量,然后用这最大的k个特征向量组成的矩阵来做低维投影降维。可以看出,在这个过程中需要先求出协方差矩阵 ,当样本数多、样本特征数也多的时候,这个计算还是很大的。当我们用到SVD分解协方差矩阵的时候,SVD有两个好处:
1、有一些SVD的实现算法可以先不求出协方差矩阵 也能求出我们的右奇异矩阵V。也就是说,我们的PCA算法可以不用做特征分解而是通过SVD来完成,这个方法在样本量很大的时候很有效。实际上,scikit-learn的PCA算法的背后真正的实现就是用的SVD,而不是特征值分解。
2、注意到PCA仅仅使用了我们SVD的左奇异矩阵,没有使用到右奇异值矩阵,那么右奇异值矩阵有什么用呢?
假设我们的样本是m*n的矩阵X,如果我们通过SVD找到了矩阵 最大的k个特征向量组成的k*n的矩阵 ,则我们可以做如下处理:
可以得到一个m*k的矩阵X',这个矩阵和我们原来m*n的矩阵X相比,列数从n减到了k,可见对列数进行了压缩。也就是说,左奇异矩阵可以用于对行数的压缩;右奇异矩阵可以用于对列(即特征维度)的压缩。这就是我们用SVD分解协方差矩阵实现PCA可以得到两个方向的PCA降维(即行和列两个方向)。
PCA具体实现
数据集介绍
ORL人脸数据集一共包含40个不同人的400张图像,此数据集下包含40个目录,每个目录下有10张图像,每个目录表示一个不同的人。所有的图像是以PGM格式存储,灰度图,图像大小宽度为92,高度为112。
具体代码实现及运行结果
数据获取
代码
%matplotlib inline
# 导入所需模块
import matplotlib.pyplot as plt
import numpy as np
import os
import cv2
# plt显示灰度图片
def plt_show(img):
plt.imshow(img,cmap='gray')
plt.show()
# 读取一个文件夹下的所有图片,输入参数是文件名,返回文件地址列表
def read_directory(directory_name):
faces_addr = []
for filename in os.listdir(directory_name):
faces_addr.append(directory_name + "/" + filename)
return faces_addr
# 读取所有人脸文件夹,保存图像地址在faces列表中
faces = []
for i in range(1,41):
faces_addr = read_directory('E:/2388412628/FileRecv/Face_Dataset/Face/ORL_Faces/s'+str(i))
for addr in faces_addr:
faces.append(addr)
# 读取图片数据,生成列表标签
images = []
labels = []
for index,face in enumerate(faces):
# enumerate函数可以同时获得索引和值
image = cv2.imread(face,0)
images.append(image)
labels.append(int(index/10+1))
print(len(labels))
print(len(images))
print(type(images[0]))
print(labels)
先读取ORL数据集下的所有图像,同时生成列表标签。下图表示一共有400个标签、400张图像、图像的数据类型以及标签的值。
输出前二十组图片
代码:
# 画出前20组人脸图像
# 创建画布和子图对象
fig, axes = plt.subplots(10,20
,figsize=(20,10)
,subplot_kw = {"xticks":[],"yticks":[]} #不要显示坐标轴
)
# 图片x行y列,画布x宽y高
# 填充图像
for i, ax in enumerate(axes.flat):
ax.imshow(images[i],cmap="gray") #选择色彩的模式
运行结果:
PCA降维
接下来把每张图片数据降到一维,a.flatten()就是把a降到一维,默认是按横的方向降,每张图片的维度是1×10304,与图片的大小92×112=10304相符,将其转换为numpy数组,方便后面的计算。
# 图像数据矩阵转换为一维
image_data = []
for image in images:
data = image.flatten()
# a是个矩阵或者数组,a.flatten()就是把a降到一维,默认是按横的方向降
image_data.append(data)
print(image_data[0].shape)
# 转换为numpy数组
X = np.array(image_data)
y = np.array(labels)
print(type(X))
print(X.shape)
运行结果
接下来导入sklearn的PCA模块,根据标签,使用train_test_split()划分数据集,训练PCA模型,保留100个维度,输出100个特征脸,可以发现越到后面人脸越模糊,意味着所占的比重越小。
代码如下:
# 导入sklearn的pca模块
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
# 画出每个图像数据降到一维后的矩阵
import pandas as pd
data = pd.DataFrame(X)
data.head()
运行结果:
然后划分数据集,训练PCA模型,输出结果
代码如下:
# 划分数据集
x_train,x_test,y_train,y_test = train_test_split(X, y, test_size=0.2) # train训练,test测试
# 训练PCA模型
pca=PCA(n_components=100) # 保留100个纬度
pca.fit(x_train) # 训练过程
# 返回训练集和测试集降维后的数据集
x_train_pca = pca.transform(x_train) # 转换过程
x_test_pca = pca.transform(x_test)
print(x_train_pca.shape) # 320个训练集,保留了100个特征
print(x_test_pca.shape) # 80个测试集,保留了100个特征
V = pca.components_
V.shape
# 100个特征脸
# 创建画布和子图对象
fig, axes = plt.subplots(10,10
,figsize=(15,15)
,subplot_kw = {"xticks":[],"yticks":[]} #不要显示坐标轴
)
#填充图像
for i, ax in enumerate(axes.flat):
ax.imshow(V[i,:].reshape(112,92),cmap="gray") #reshape规定图片的大小,选择色彩的模式
运行结果:
可以看出来,虽然我们把图片的维度从10304维降低到100维,但是我们还是可以看出图片的大致人脸形状,但是数据量就大大的减小了,每张图片降低了10000维度,这对我们数据处理等操作提供了很大的便利。
我们来看看降到100维的图片还保留了原来多少信息
pca.explained_variance_ratio_
# 返回特征所携带的数据是原始数据的多少
pca.explained_variance_ratio_.sum()
运行结果
可以看到,虽然降到了100维但依旧保留了90%的信息,可见PAC的强大之处。
总结
主成分分析(PCA)是一种常用的多变量数据降维技术,具有广泛的应用领域。本次实验旨在通过PCA方法对数据集进行降维,经过实验,我们发现,通过PCA降维后,仅保留100个维度ORL人脸数据集依旧能保存90%的图片信息,而且还可以大大减少数据存储和处理的复杂度。PCA可以将原始数据降到较低维度,从而提高算法的效率和准确性。在这个实验中,首先读取了所有人脸图片,并将其转换为一维数组。然后使用PCA模型对训练集进行训练,并将训练集和测试集分别进行降维处理。最后,展示了前100个特征脸,并输出了每个新特征向量所占的信息量、特征所携带的数据等信息。
PCA的优点:
-
可以减少数据集中的噪声。PCA可以通过降维来去除数据中的噪声,从而提高模型的精度和可靠性。
-
可以提高算法的效率。通过降维处理,PCA可以减少特征数量,从而提高算法的效率。
-
可以揭示数据背后的本质特征。PCA可以将原始数据转换为新的特征向量,这些特征向量表示数据背后的本质特征,有助于理解数据的本质结构和规律。
PCA的缺点:
-
不能处理非线性关系。PCA是一种线性变换方法,无法处理非线性关系的数据。
-
容易受到极端值干扰。PCA的计算过程涉及到协方差矩阵的计算,如果数据集中存在极端值,则协方差矩阵可能会失真,从而导致PCA的效果不佳。
-
可能会丢失一些重要信息。PCA通常会将数据降维到一个较低的维度,这可能会导致一些重要信息被丢失。