主成分分析(PCA)是一种无监督的线性降维算法,核心思想是通过正交变换将原始高维数据投影到低维空间,得到一组互不相关的新特征,也就是主成分,这些主成分能够保留原始数据的大部分信息。在Python中实现主成分分析,既可以调用成熟的机器学习库快速完成,也可以基于原理手动编写代码实现,两种方式各有适用场景。

主成分分析的核心步骤
无论使用哪种方式实现,主成分分析的核心流程都包含以下几个环节:
- 数据标准化:消除不同特征量纲差异对结果的影响,通常将特征缩放到均值为0、方差为1的范围
- 计算协方差矩阵:衡量不同特征之间的线性相关性
- 计算协方差矩阵的特征值和特征向量:特征值代表对应主成分的方差大小,也就是信息含量
- 选择主成分:按照特征值从大到小排序,选择前k个特征向量作为投影矩阵
- 数据投影:将原始数据乘以投影矩阵,得到降维后的新数据
使用sklearn库快速实现主成分分析
sklearn库内置了PCA类,封装了完整的实现逻辑,适合快速完成降维任务,不需要手动处理复杂的矩阵运算。下面以经典的鸢尾花数据集为例,演示具体的使用方式。
完整代码示例
import numpy as np
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
# 1. 加载数据集
iris = load_iris()
X = iris.data # 特征数据,共4个特征
y = iris.target # 标签数据
feature_names = iris.feature_names
# 2. 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 3. 初始化PCA模型,指定降维到2维
pca = PCA(n_components=2)
# 4. 拟合数据并转换
X_pca = pca.fit_transform(X_scaled)
# 5. 查看主成分相关信息
print("主成分方差占比:", pca.explained_variance_ratio_)
print("累计方差占比:", np.cumsum(pca.explained_variance_ratio_))
print("主成分对应的特征向量形状:", pca.components_.shape)
# 6. 可视化降维后的结果
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap='viridis')
plt.xlabel('第一主成分')
plt.ylabel('第二主成分')
plt.title('PCA降维后的鸢尾花数据分布')
plt.show()
上述代码中,StandardScaler用于完成数据标准化,PCA类的n_components参数指定要保留的主成分数量,这里设置为2是为了方便可视化。explained_variance_ratio_属性可以查看每个主成分保留的原始数据方差比例,累计值越高说明降维后保留的信息越多。
基于numpy手动实现主成分分析
如果需要深入理解主成分分析的原理,可以基于numpy手动实现整个流程,核心就是按照前面提到的步骤完成矩阵运算。
完整代码示例
import numpy as np
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
def manual_pca(X, k):
"""
手动实现主成分分析
:param X: 标准化后的原始数据,形状为(n_samples, n_features)
:param k: 要保留的主成分数量
:return: 降维后的数据,投影矩阵
"""
# 1. 计算协方差矩阵
cov_matrix = np.cov(X.T) # 转置后计算,得到n_features x n_features的协方差矩阵
# 2. 计算协方差矩阵的特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# 3. 将特征值和特征向量按特征值从大到小排序
sorted_indices = np.argsort(eigenvalues)[::-1] # 从大到小排序的索引
sorted_eigenvalues = eigenvalues[sorted_indices]
sorted_eigenvectors = eigenvectors[:, sorted_indices]
# 4. 选择前k个特征向量作为投影矩阵
projection_matrix = sorted_eigenvectors[:, :k]
# 5. 将数据投影到主成分空间
X_pca = np.dot(X, projection_matrix)
# 计算方差占比
explained_variance_ratio = sorted_eigenvalues[:k] / np.sum(sorted_eigenvalues)
print("手动实现的主成分方差占比:", explained_variance_ratio)
print("累计方差占比:", np.cumsum(explained_variance_ratio))
return X_pca, projection_matrix
# 加载数据并标准化
iris = load_iris()
X = iris.data
y = iris.target
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 调用手动实现的PCA,降维到2维
X_pca_manual, projection_mat = manual_pca(X_scaled, k=2)
# 可视化结果
plt.scatter(X_pca_manual[:, 0], X_pca_manual[:, 1], c=y, cmap='viridis')
plt.xlabel('第一主成分')
plt.ylabel('第二主成分')
plt.title('手动实现PCA降维后的鸢尾花数据分布')
plt.show()
手动实现的过程中,np.cov用于计算协方差矩阵,np.linalg.eig用于计算矩阵的特征值和特征向量,排序后取前k个特征向量组成投影矩阵,最后通过矩阵乘法完成数据投影。得到的结果和sklearn的实现是一致的,只是缺少了更多的参数优化和异常处理逻辑。
关键参数说明
在使用sklearn的PCA类时,有几个常用参数需要了解:
- n_components:指定要保留的主成分数量,可以是整数,也可以是0到1之间的小数,表示要保留的方差比例,比如设置为0.95,会自动选择保留95%方差所需的主成分数量
- svd_solver:指定奇异值分解的方法,默认是auto,会根据数据规模自动选择,大规模数据可以选择randomized提升计算速度
- whiten:是否对主成分进行白化处理,白化后每个主成分的方差为1,默认是False
适用场景和注意事项
主成分分析适合处理线性相关的数据,对于非线性数据结构效果较差,此时可以考虑使用核主成分分析等非线性降维方法。另外,主成分分析是对特征的变换,会丢失原始特征的实际含义,降维后的新特征无法直接对应原始的业务含义,使用时需要结合具体场景判断是否满足需求。
如果数据中存在大量缺失值,需要先完成缺失值填充再进行主成分分析,否则会影响协方差矩阵的计算结果,导致降维效果偏差。同时标准化步骤不能省略,尤其是不同特征量纲差异较大时,不标准化会让数值大的特征主导主成分的结果。