目录
4、主成分分析(Principal Component Analysis)
前言:
在机器学习领域,特征维度约减是一个重要的技术。随着数据集的增大和特征的增加,高维数据分析变得越来越具有挑战性。为了解决这个问题,我们需要一种有效的方法来减少特征维度,同时保留数据的最重要信息。本文将介绍主成分分析(Principal Component Analysis, PCA)作为一种常用的维度约减方法。
一、理论介绍
1、维度约减的概念
在机器学习和数据科学中,特征维度是指一个数据集中每个样本的属性数量。例如,一个包含1000张图像的数据集,每张图像都有1000个像素点,那么每个图像就有1000个特征。
高维数据集通常会带来一些挑战。首先,计算复杂度会大大增加,因为需要处理更多的特征。其次,高维数据集容易导致过拟合问题,尤其是在训练样本数量相对较少的情况下。此外,高维数据集还可能包含冗余信息,这会使模型变得不够简洁和可解释。
维度约减的目的是解决这些挑战,它可以将高维特征向量映射到低维子空间中,从而简化计算、提高模型效果、降低存储需求等。当我们进行维度约减时,我们要保留尽可能多的有用信息,同时舍弃冗余和无效信息。
例如,给定n个样本(每个样本维度为p维) : {x1 , x2 ,..., xn }
通过特征变换/投影矩阵实现特征空间的压缩:
2、为何要维度约减
在机器学习和数据分析中,数据集过多的特征不仅增加了计算、存储和处理的复杂度,还可能导致“维度灾难”问题,使得模型出现过拟合等问题。维度约减就是通过某种方法将原始数据集的特征维度降低到一个更小的维度空间,以达到优化模型性能和减少计算成本的目的。
具体来说,维度约减有以下几个好处:
计算复杂度降低:维度越高,计算复杂度也就越高。当特征维度很高时,算法需要更多的计算时间和内存才能处理数据。因此,将数据集的维度降低可以减少计算复杂度,从而提高算法效率。
模型性能优化:当数据维度很高时,模型容易出现过拟合的问题。过拟合表明模型太过复杂,能够很好地拟合训练数据,但在测试数据上表现不佳。这时候,维度约减可以有效减少过拟合的风险,简化模型,提高泛化性能。
降噪:数据中的噪音和冗余特征可以影响模型的性能。通过维度约减,可以减少噪音和冗余特征对模型的影响,从而提高模型的精度和可靠性。
可视化和解释:通过维度约减,我们可以将数据映射到一个更小的维度空间中,并可视化展示数据结构和关系。这样有助于更好地理解数据,发现数据中隐藏的模式和规律,从而更好地进行数据分析和决策。
3、常规维度约减方法
常规维度约减方法主要有两种:特征选择和特征提取。
特征选择
特征选择是从原始特征集合中选择出最相关、最有用的特征,丢弃与目标预测无关或者冗余的特征。这种方法可以减少计算复杂度,提高算法效率。特征选择的具体方法包括:
- 过滤法(Filter):根据某些准则(如相关系数、卡方检验等)对每个特征进行评估,并选择出最相关的特征。
- 包装法(Wrapper):将特征选择看作一个优化问题,通过构建模型并评估模型效果来选择特征。
- 嵌入法(Embedded):特征选择作为模型训练的一部分,通过正则化、Lasso回归等方法来选择特征。
特征提取
特征提取是将原始特征映射到一个新的低维空间,从而得到更为紧凑、有效的表示。这种方法可以减少冗余信息、降低维度,并保留数据的最重要信息。常见的特征提取方法包括:
- 主成分分析(PCA):通过线性变换,将原始数据映射到主成分组成的新坐标系下,从而实现维度约减。
- 线性判别分析(LDA):通过线性变换将原始数据映射到一个新的低维空间,最大化类间距离和最小化类内距离。
- 核主成分分析(KPCA):将非线性数据映射到更高维的特征空间,通过PCA在该空间中进行特征提取。
总体来说,特征选择和特征提取是维度约减中两种常见的方法。不同方法的选择取决于特定问题、数据集和算法的需求,需要根据具体情况进行权衡和选择。
4、主成分分析(Principal Component Analysis)
PCA是一种无监督的线性降维方法,通过将原始数据投影到新的特征空间中的主成分上来实现维度约减。新的特征被称为主成分。这些主成分是按照方差大小排序的,保留前几个主成分即可达到维度约减的目的。通过保留具有最大方差的主成分,PCA 可以捕获数据中的最重要信息。
基本思路:通过协方差分析,建立高维空间到低维空间的线性映射/矩阵,保留尽可能多的样本信息。压缩后的数据对分类、聚类尽量不产生影响,甚至有所提升
PCA的目标是找到新的低维坐标系,使得在该坐标系下数据的方差最大化。方差较大的方向表示了数据中的主要信息。
PCA的流程:
- 对数据集进行去均值处理,使每个特征的平均值为0;
- 计算数据集的协方差矩阵;
- 对协方差矩阵进行特征值分解,得到特征向量和特征值;
- 选择前k个最大的特征值对应的特征向量作为主成分;
- 将数据集投影到选定的主成分上,得到降维后的数据。
二、代码实现
1、手动实现简易PCA
1)导入所需的库,包括NumPy用于数值计算、make_blobs用于生成示例数据集、和matplotlib.pyplot用于数据可视化。
import numpy as np
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
2)使用make_blobs函数生成一个包含三个聚类中心的二维示例数据集,其中有1000个样本点。X是包含特征的数据矩阵,y是包含标签的向量。
# 生成示例数据集
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, random_state=42)
3)对数据进行标准化,通过减去每个特征的均值并除以每个特征的标准差,使得数据具有零均值和单位方差。计算数据的协方差矩阵,其中X.T表示X的转置。
# 数据标准化
X = (X - X.mean(axis=0)) / X.std(axis=0)
# 计算协方差矩阵
cov_mat = np.cov(X.T)
4)使用numpy.linalg.eig函数计算协方差矩阵的特征值和特征向量。然后将特征值按照从大到小的顺序进行排序,并相应地重新排列特征向量。
# 将特征值从大到小排序
idx = np.argsort(eig_vals)[::-1]
eig_vals = eig_vals[idx]
eig_vecs = eig_vecs[:, idx]
# 选择前两个主成分
pc1 = eig_vecs[:, 0]
pc2 = eig_vecs[:, 1]
5)最后选择排名前两个的特征向量作为前两个主成分。
完整代码:
import numpy as np
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
# 生成示例数据集
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, random_state=42)
# 数据标准化
X = (X - X.mean(axis=0)) / X.std(axis=0)
# 计算协方差矩阵
cov_mat = np.cov(X.T)
# 计算特征值和特征向量
eig_vals, eig_vecs = np.linalg.eig(cov_mat)
# 将特征值从大到小排序
idx = np.argsort(eig_vals)[::-1]
eig_vals = eig_vals[idx]
eig_vecs = eig_vecs[:, idx]
# 选择前两个主成分
pc1 = eig_vecs[:, 0]
pc2 = eig_vecs[:, 1]
# 可视化结果
plt.scatter(X[:, 0], X[:, 1], alpha=0.5)
plt.arrow(0, 0, pc1[0], pc1[1], width=0.1, color='red', label='PC1')
plt.arrow(0, 0, pc2[0], pc2[1], width=0.1, color='blue', label='PC2')
plt.legend()
plt.show()
运行结果:
2、PCA实现简单人脸识别
import os
import cv2
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# 1. 定义一个函数用于将人脸图像矢量化为一个向量
def vectorize_image(image_path):
image = cv2.imread(image_path, 0) # 以灰度模式读取图像
vector = image.flatten() # 将图像转化为一维向量
return vector
# 2. 定义一个函数用来选取训练图片,并对每张图片进行矢量化处理
def process_images(folder_path):
image_vectors = []
for person_folder in os.listdir(folder_path):
person_folder_path = os.path.join(folder_path, person_folder)
if not os.path.isdir(person_folder_path):
continue
for image_filename in os.listdir(person_folder_path):
image_path = os.path.join(person_folder_path, image_filename)
if not image_filename.endswith('.tif'):
continue
vector = vectorize_image(image_path)
image_vectors.append(vector)
return np.array(image_vectors)
# 3. 进行PCA算法的降维操作
def apply_pca(image_vectors, num_components=2):
pca = PCA(n_components=num_components)
pca.fit(image_vectors)
transformed_vectors = pca.transform(image_vectors)
return transformed_vectors
# 4. 定义一个可视化函数
def visualize_data(data, labels):
plt.scatter(data[:, 0], data[:, 1], c=labels)
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.show()
# 5. 定义一个人脸识别函数
def face_recognition(image_path, training_data, labels):
test_vector = vectorize_image(image_path)
pca = PCA(n_components=2)
pca.fit(training_data)
test_vector_transformed = pca.transform([test_vector])
training_data_transformed = pca.transform(training_data)
distances = np.linalg.norm(training_data_transformed - test_vector_transformed, axis=1)
closest_index = np.argmin(distances)
predicted_label = labels[closest_index]
return predicted_label
# 主程序
folder_path = 'Face/FERET_Face'
training_data = process_images(folder_path)
# 生成标签(假设每个人的图片数量都是7)
labels = np.repeat(np.arange(200), 7)
# 进行PCA降维操作
transformed_data = apply_pca(training_data)
# 可视化降维后的数据
visualize_data(transformed_data, labels)
# 测试人脸识别函数
test_image_path = 'Face/FERET_Face/FERET-001/01.tif'
predicted_label = face_recognition(test_image_path, training_data, labels)
print("Predicted label:", predicted_label)
-
vectorize_image(image_path)
:该函数用于将人脸图像矢量化为一个向量。它首先使用OpenCV库中的cv2.imread()
函数以灰度模式读取图像,然后使用flatten()
函数将图像转化为一维向量,并返回该向量。 -
process_images(folder_path)
:该函数用于选取训练图片,并对每张图片进行矢量化处理。它首先遍历给定文件夹路径下的每个子文件夹,然后针对每个子文件夹,遍历文件夹内的每张图片。对于每张以".tif"结尾的图片,调用vectorize_image()
函数将其矢量化,并将矢量添加到一个列表中。最后,将列表转化为NumPy数组并返回。 -
apply_pca(image_vectors, num_components=2)
:该函数用于进行PCA算法的降维操作。它首先创建一个PCA对象,并指定要保留的主成分数量(默认为2)。然后使用fit()
函数拟合给定的训练数据,再使用transform()
函数对训练数据进行降维操作,并返回降维后的数据。 -
visualize_data(data, labels)
:该函数用于可视化降维后的数据。它使用Matplotlib库绘制散点图,其中x轴和y轴分别表示主成分1和主成分2,颜色表示对应的标签。 -
face_recognition(image_path, training_data, labels)
:该函数用于进行人脸识别。它首先调用vectorize_image()
函数将待测试的人脸图像矢量化。然后创建一个PCA对象,并使用训练数据拟合该对象。接下来,使用transform()
函数将测试数据和训练数据分别降维。计算测试数据与每个训练数据之间的欧氏距离,并找到距离最近的训练数据的索引。最后,根据该索引找到对应的标签,并返回预测结果。
运行结果:
由于我们使用FERET人脸数据库的第一张图像作为测试图像,该图像与训练数据中的第一张图像是相似的,因此返回的匹配索引为0。
三、实验小结
在本次实验中,我们通过对数据集进行PCA降维,我们成功地将原始数据从高维度(转换为低维度表示。降维后的数据保留了原始数据的主要信息,能够有效地减少数据的冗余性。并且通过将降维后的数据可视化,我们可以更好地理解数据的结构和分布。
总之,PCA是一种非常有用的降维算法,可以有效地处理高维数据,并在一定程度上提高模型准确率。在实际应用中,我们可以根据具体问题和数据特征来选择合适的主成分数量,从而得到更好的降维效果。