PCA算法
PCA原理
PCA算法,即主成分分析方法,是一种常用的数据分析方法。通过线性变换将原始数据转换成一组新的变量,即主成分。通过主成分最大程度上保存原始数据的方差信息,同时实现数据的降维。
主要思想:将n维特征映射到k维上,这k维是全新的正交特征,也被称为主成分,是在原n维特征的基础上重新构造出来的k特征。
具体实现:从原始是空间中顺序地找到一组相互正交的坐标轴,新的坐标轴的选取与数据本身是密切相关的。坐标选择如下表:
| 新坐标轴 | 选择依据 |
|---|---|
| 第一个新坐标轴 | 原始数据中方差最大的方向 |
| 第二个新坐标轴 | 与第一个坐标轴正交的平面中使得方差最大的方向 |
| 第三个新坐标轴 | 与第1,2个轴正交的平面中方差最大的方向 |
| …… | 依次类推,可以得到n个这样的坐标轴。 |
通过这种方式获得的新的坐标轴,大部分方差都包含在前面k个坐标轴中,后面的坐标轴所含的方差几乎为0。所以可以忽略余下的坐标轴,只保留前面k个含有绝大部分方差的坐标轴。
事实上,这相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为0的特征维度,实现对数据特征的降维处理。有助于简化数据结构、减少计算量,可提取数据中最有价值的信息。
算法流程
以下是手动PCA算法实现的流程
根据PCA算法是实现流程可知,PCA算法是核心目标是"降维+保留信息"。即将高维数据映射到低维空间内,解决高维度数据带来的问题。PCA通过线性变换将原始数据转换成一组新的变量(即"坐标轴"),即主成分。
实验实现
-
1. 实验目的
分别进行手动实现PCA算法和用sklearn进行PCA算法的实现,实现对算法的学习和理解。
要求:手动实现PCA算法,标准化数据,确保每个特征的均值为零;将数据降维到2维。 -
2. 数据准备
使用sklearn库中的iris作为实验数据集,其中每个样本有4个特征参数,分别为花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性。 -
3. 实验流程手动实现
PCA算法实验流程:用
sklearn进行PCA算法:实现方法比较简单,直接使用scikit-learn的PCA类实现降维,最后用matplotlib进行数据可视化即可。 -
4. 代码实现
数据集选取
选用鸢尾花数据集(Iris dataset),通过sklearn.datasets中的load_iris()函数进行加载,数据存储在X(特征数据)和y(目标数据)中。iris = load_iris() X = iris.data y = iris.target方法一:手动实现
PCA算法
①数据标准化# 数据去中心化,使得数据的均值变为 0 def standardize_data(X): mean = np.mean(X, axis=0) X_centered = X - mean return X_centered X_centered = standardize_data(X) print("中心化后的数据(前五行):") print(X_centered[:5])②求协方差矩阵代码
def calculate_covariance_matrix(X): cov_matrix = np.cov(X, rowvar=False) return cov_matrix cov_matrix = calculate_covariance_matrix(X_centered) print("协方差矩阵:") print(cov_matrix)③求特征值和特征向量代码
# 求特征值和特征向量 # 特征值λ和特征向量v满足方程Av = λv def calculate_eigenvalues_eigenvectors(cov_matrix): eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) return eigenvalues, eigenvectors eigenvalues, eigenvectors = calculate_eigenvalues_eigenvectors(cov_matrix) print("特征值:\n", eigenvalues) print("特征向量:\n", eigenvectors)④将数据降到
2维# 将数据降到2维 # 按照特征值的大小对特征向量进行排序,选择前K个特征向量,被选中的特征向量所构成的矩阵就是投影矩阵 # 将中心化后的数据与投影矩阵相乘 def reduce_dimension(X, k): idx = np.argsort(eigenvalues)[::-1][:k] selected_eigenvectors = eigenvectors[:, idx] # 为方便对比两种方法的结果,尝试保持特征向量方向与sklearn一致 pca = PCA(n_components=k) pca.fit(X_centered) sklearn_eigenvectors = pca.components_.T for i in range(k): if np.dot(selected_eigenvectors[:, i], sklearn_eigenvectors[:, i]) < 0: selected_eigenvectors[:, i] *= -1 X_reduced = X_centered.dot(selected_eigenvectors) return X_reduced X_reduced_manual = reduce_dimension(X, 2) print("手动实现PCA降维后的数据(前五行):") print(X_reduced_manual[:5])方法二:用
sklearn进行PCA算法# 导入模块 from sklearn.decomposition import PCA算法实现
pca = PCA(n_components=2) X_reduced_sklearn = pca.fit_transform(X) print("使用sklearn实现PCA降维后的数据(前五行):") print(X_reduced_sklearn[:5])结果可视化
# 4. 可视化原始数据和降维后的数据 plt.figure(figsize=(12, 5)) # 原始数据 plt.subplot(1, 3, 1) plt.scatter(X[:, 0], X[:, 1], c=y) plt.title('Original Data') # 手动实现PCA降维后的数据 plt.subplot(1, 3, 2) plt.scatter(X_reduced_manual[:, 0], X_reduced_manual[:, 1], c=y) plt.title('PCA (Manual) Reduced Data') # sklearn实现PCA降维后的数据 plt.subplot(1, 3, 3) plt.scatter(X_reduced_sklearn[:, 0], X_reduced_sklearn[:, 1], c=y) plt.title('PCA (sklearn) Reduced Data') plt.show()完整实现代码
import numpy as np from sklearn.datasets import load_iris from sklearn.decomposition import PCA import matplotlib.pyplot as plt # 1. 数据加载 iris = load_iris() X = iris.data y = iris.target # 2. 方法一:手动实现PCA # 数据去中心化,使得数据的均值变为 0 def standardize_data(X): mean = np.mean(X, axis=0) X_centered = X - mean return X_centered X_centered = standardize_data(X) print("中心化后的数据(前五行):") print(X_centered[:5]) # 求协方差矩阵 def calculate_covariance_matrix(X): cov_matrix = np.cov(X, rowvar=False) return cov_matrix cov_matrix = calculate_covariance_matrix(X_centered) print("协方差矩阵:") print(cov_matrix) # 求特征值和特征向量 # 特征值λ和特征向量v满足方程Av = λv def calculate_eigenvalues_eigenvectors(cov_matrix): eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) return eigenvalues, eigenvectors eigenvalues, eigenvectors = calculate_eigenvalues_eigenvectors(cov_matrix) print("特征值:\n", eigenvalues) print("特征向量:\n", eigenvectors) # 将数据降到2维 # 按照特征值的大小对特征向量进行排序,选择前K个特征向量,被选中的特征向量所构成的矩阵就是投影矩阵 # 将中心化后的数据与投影矩阵相乘 def reduce_dimension(X, k): idx = np.argsort(eigenvalues)[::-1][:k] selected_eigenvectors = eigenvectors[:, idx] # 为方便对比两种方法的结果,尝试保持特征向量方向与sklearn一致 pca = PCA(n_components=k) pca.fit(X_centered) sklearn_eigenvectors = pca.components_.T for i in range(k): if np.dot(selected_eigenvectors[:, i], sklearn_eigenvectors[:, i]) < 0: selected_eigenvectors[:, i] *= -1 X_reduced = X_centered.dot(selected_eigenvectors) return X_reduced X_reduced_manual = reduce_dimension(X, 2) print("手动实现PCA降维后的数据(前五行):") print(X_reduced_manual[:5]) # 3. 方法二:使用sklearn进行PCA pca = PCA(n_components=2) X_reduced_sklearn = pca.fit_transform(X) print("使用sklearn实现PCA降维后的数据(前五行):") print(X_reduced_sklearn[:5]) # 4. 可视化原始数据和降维后的数据 plt.figure(figsize=(12, 5)) # 原始数据 plt.subplot(1, 3, 1) plt.scatter(X[:, 0], X[:, 1], c=y) plt.title('Original Data') # 手动实现PCA降维后的数据 plt.subplot(1, 3, 2) plt.scatter(X_reduced_manual[:, 0], X_reduced_manual[:, 1], c=y) plt.title('PCA (Manual) Reduced Data') # sklearn实现PCA降维后的数据 plt.subplot(1, 3, 3) plt.scatter(X_reduced_sklearn[:, 0], X_reduced_sklearn[:, 1], c=y) plt.title('PCA (sklearn) Reduced Data') plt.show()实验结果
中心化后的数据(前五行): [[-0.74333333 0.44266667 -2.358 -0.99933333] [-0.94333333 -0.05733333 -2.358 -0.99933333] [-1.14333333 0.14266667 -2.458 -0.99933333] [-1.24333333 0.04266667 -2.258 -0.99933333] [-0.84333333 0.54266667 -2.358 -0.99933333]] 协方差矩阵: [[ 0.68569351 -0.042434 1.27431544 0.51627069] [-0.042434 0.18997942 -0.32965638 -0.12163937] [ 1.27431544 -0.32965638 3.11627785 1.2956094 ] [ 0.51627069 -0.12163937 1.2956094 0.58100626]] 特征值: [4.22824171 0.24267075 0.0782095 0.02383509] 特征向量: [[ 0.36138659 -0.65658877 -0.58202985 0.31548719] [-0.08452251 -0.73016143 0.59791083 -0.3197231 ] [ 0.85667061 0.17337266 0.07623608 -0.47983899] [ 0.3582892 0.07548102 0.54583143 0.75365743]] 手动实现PCA降维后的数据(前五行): [[-2.68412563 0.31939725] [-2.71414169 -0.17700123] [-2.88899057 -0.14494943] [-2.74534286 -0.31829898] [-2.72871654 0.32675451]] 使用sklearn实现PCA降维后的数据(前五行): [[-2.68412563 0.31939725] [-2.71414169 -0.17700123] [-2.88899057 -0.14494943] [-2.74534286 -0.31829898] [-2.72871654 0.32675451]]