机器学习 - PCA 可视化案例
想象一下,你正在整理一个塞满各种物品的杂乱房间,为了更清晰地了解房间的布局,你可能会从不同角度(比如正面、侧面、俯视)给它拍几张照片。
主成分分析(Principal Component Analysis,简称 PCA) 在机器学习中所做的事情与此类似。
PCA 是一种强大的 数据降维 和 可视化 工具。当我们的数据包含成百上千个特征(维度)时,这些数据就像身处一个超高维度的空间中,人类无法直观理解。
PCA 可以帮助我们找到数据中最重要的视角(即主成分),将数据投影到最重要的两三个维度上,从而让我们能够用二维或三维散点图来观察高维数据的结构和分布。
简单来说,PCA的目标是:
- 降维 :用更少的特征来代表原始数据,减少计算量和存储空间,同时去除噪声。
- 可视化 :将高维数据降至2维或3维,以便于我们直观地观察数据点之间的关系(如聚类、分离情况)。
PCA 核心原理与工作流程
PCA 的核心思想是寻找数据方差最大的方向。
方差越大,意味着数据在这个方向上的投影点越分散,所包含的信息量也就越多。
第一个找到的方向就是 第一主成分(PC1) ,第二个与 PC1 正交且方差次大的方向是 第二主成分(PC2) ,以此类推。
PCA 工作流程图
流程关键步骤说明:
标准化 :让每个特征的平均值为 0,标准差为 1,确保所有特征在计算时具有同等重要性。
协方差矩阵 :计算特征之间的相关性。PCA 通过分析这个矩阵来找到数据变化的主要方向。
特征值与特征向量 :
- 特征向量 :就是我们要找的主成分方向。
- 特征值 :对应特征向量方向上的数据方差大小。特征值越大,该主成分越重要。
选择主成分 :我们将特征值从大到小排序,选择前 K 个最大的特征值对应的特征向量。K 就是我们想要降维到的目标维度(例如,对于可视化,K=2 或 3)。
数据转换 :用选出的 K 个特征向量组成一个投影矩阵,将原始数据点乘这个矩阵,就得到了在 K 个新主成分上的坐标,即降维后的数据。
实战案例:鸢尾花数据集的可视化
我们将使用经典的 鸢尾花(Iris)数据集 来演示PCA。这个数据集包含150个样本,每个样本有4个特征(萼片长度、萼片宽度、花瓣长度、花瓣宽度),并属于3个不同的品种。
我们的目标是:将这 4 维的数据用 PCA 降到 2 维,并在二维平面上画出来,观察不同品种的花是否能被区分开。
环境准备与数据加载
首先,确保你安装了必要的Python库:
scikit-learn
,
matplotlib
,
numpy
,
pandas
。
# 导入必要的库importnumpyasnpimportpandasaspdimportmatplotlib.pyplotaspltfromsklearnimportdatasetsfromsklearn.decompositionimportPCAfromsklearn.preprocessingimportStandardScaler# 设置中文字体和图表样式(可选)plt.rcParams['font.sans-serif']=['SimHei']# 用来正常显示中文标签plt.rcParams['axes.unicode_minus']=False# 用来正常显示负号# 加载鸢尾花数据集iris=datasets.load_iris()X=iris.data# 特征数据,形状为 (150, 4)y=iris.target# 目标标签(品种),形状为 (150,)target_names=iris.target_names# 品种名称:['setosa', 'versicolor', 'virginica']print(f"数据集形状: {X.shape}")print(f"特征名称: {iris.feature_names}")print(f"目标类别: {target_names}")
输出:
数据集形状: (150, 4) 特征名称: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] 目标类别: ['setosa' 'versicolor' 'virginica']
数据标准化
在应用 PCA 之前,对数据进行标准化是 至关重要 的一步。
因为 PCA 对特征的尺度非常敏感,如果一个特征的数值范围(例如花瓣长度以厘米计,数值在 1-10 之间)远大于另一个特征(例如萼片宽度以毫米计,数值在 0.1-1 之间),那么数值范围大的特征会主导主成分的方向,这通常不是我们想要的。
# 数据标准化(去中心化并缩放到单位方差)scaler=StandardScaler()X_scaled=scaler.fit_transform(X)print("标准化后,前5个样本的数据:")print(X_scaled[:5])
应用 PCA 进行降维
我们使用
scikit-learn
的
PCA
类,它可以轻松完成所有数学计算。
# 创建PCA对象,指定降维到2维pca=PCA(n_components=2)# 在标准化后的数据上拟合PCA模型,并进行数据转换X_pca=pca.fit_transform(X_scaled)print(f"降维后的数据形状: {X_pca.shape}")print(f"前5个样本在PC1和PC2上的坐标:\n{X_pca[:5]}")# 查看各主成分的方差解释率print(f"主成分方差解释率: {pca.explained_variance_ratio_}")print(f"前两个主成分累计方差解释率: {sum(pca.explained_variance_ratio_):.4f}")
代码解析:
n_components=2
:指定我们要将数据降至 2 维。
fit_transform(X_scaled)
:该方法一次性完成两件事:
-
fit:根据输入数据X_scaled计算 PCA 所需的参数(如主成分方向)。 -
transform:使用计算好的参数,将数据X_scaled转换到新的二维空间。
explained_variance_ratio_
:这是一个非常重要的属性。它告诉我们每个主成分
捕获的原始数据方差的比例
。例如,如果输出是
[0.73, 0.23]
,意味着PC1保留了原始数据73%的信息,PC2保留了23%的信息,两者加起来保留了96%的信息。这帮助我们评估降维后的信息损失。
可视化结果
现在,我们有了二维数据
X_pca
,可以轻松地用散点图将其可视化。
# 创建可视化图表plt.figure(figsize=(8,6))# 为每个品种设置不同的颜色和标记colors=['navy','turquoise','darkorange']lw=2# 线宽# 遍历三个品种,分别绘制forcolor,i,target_nameinzip(colors,[0,1,2],target_names):plt.scatter(X_pca[y==i,0],# 选择属于当前品种i的样本的PC1坐标X_pca[y==i,1],# 选择属于当前品种i的样本的PC2坐标color=color,alpha=0.8,lw=lw,label=target_name)# 添加图表标题和坐标轴标签plt.title('鸢尾花数据集的PCA二维可视化')plt.xlabel(f'第一主成分 (PC1) - 方差解释率: {pca.explained_variance_ratio_[0]:.2%}')plt.ylabel(f'第二主成分 (PC2) - 方差解释率: {pca.explained_variance_ratio_[1]:.2%}')plt.legend(loc='best',shadow=False,scatterpoints=1)plt.grid(True,linestyle='--',alpha=0.6)# 显示图表plt.tight_layout()plt.show()
可视化结果解读: 运行上述代码后,你会得到一张二维散点图。
- X轴(PC1) :代表了原始4个特征中方差最大的方向,是区分数据最重要的维度。从图中可以看出,它很好地将 Setosa(山鸢尾) 品种与其他两个品种分离开。
- Y轴(PC2) :代表了与PC1正交且方差次大的方向,提供了额外的区分信息。它帮助进一步区分 Versicolor(杂色鸢尾) 和 Virginica(维吉尼亚鸢尾) ,尽管两者有一些重叠。
- 结论 :通过PCA,我们成功将4维数据投影到2维平面,并清晰地观察到三个品种的聚类情况。Setosa完全分离,而Versicolor和Virginica在二维投影上存在部分重叠,这说明仅用前两个主成分(保留了约95%的信息)还不足以完美区分后两个品种,但它们的主要分布趋势已经非常明显。
深入探索与思考
如何选择主成分的数量(K值)?
在实际项目中,我们可能不知道应该降到几维。一个常用的方法是绘制 碎石图(Scree Plot) ,它展示了每个主成分的方差解释率。
# 首先,用所有主成分拟合PCApca_full=PCA()pca_full.fit(X_scaled)# 绘制碎石图plt.figure(figsize=(8,5))plt.plot(range(1,len(pca_full.explained_variance_ratio_)+1),pca_full.explained_variance_ratio_,'o-',linewidth=2)plt.title('PCA方差解释率碎石图')plt.xlabel('主成分序号')plt.ylabel('方差解释率')plt.grid(True,linestyle='--',alpha=0.6)plt.xticks(range(1,len(pca_full.explained_variance_ratio_)+1))plt.tight_layout()plt.show()# 绘制累计方差解释率图plt.figure(figsize=(8,5))plt.plot(range(1,len(pca_full.explained_variance_ratio_)+1),np.cumsum(pca_full.explained_variance_ratio_),'s-',linewidth=2,color='red')plt.title('PCA累计方差解释率')plt.xlabel('主成分数量')plt.ylabel('累计方差解释率')plt.axhline(y=0.95,color='gray',linestyle='--',label='95% 阈值')# 常用阈值plt.legend()plt.grid(True,linestyle='--',alpha=0.6)plt.xticks(range(1,len(pca_full.explained_variance_ratio_)+1))plt.tight_layout()plt.show()
如何选择 K 值?
- 看拐点 :在碎石图中,寻找方差解释率下降趋势突然变缓的点(即肘部),其后的主成分贡献较小。
- 设定阈值 :在累计方差图中,选择能使累计解释率达到一个满意阈值(如 95% 或 99%)的最小K值。从鸢尾花数据的累计图可以看出,前两个主成分已能解释超过 95% 的方差,因此 K=2 是一个很好的选择。
理解主成分的含义
我们还可以查看主成分的 载荷(Loadings) ,即每个原始特征对主成分的贡献权重,这有助于解释主成分的实际意义。
# 获取前两个主成分的载荷矩阵(特征向量)pca_components=pca.components_# 形状为 (2, 4)# 用DataFrame展示,更清晰df_components=pd.DataFrame(pca_components,columns=iris.feature_names,index=['PC1','PC2'])print("主成分载荷矩阵(特征向量):")print(df_components)# 可以用热力图可视化importseabornassnsplt.figure(figsize=(8,4))sns.heatmap(df_components,annot=True,cmap='RdBu_r',center=0)plt.title('主成分载荷热力图')plt.tight_layout()plt.show()
解读载荷矩阵:
- 对于 PC1 ,如果花瓣长度和花瓣宽度有较大的 正 权重,而萼片宽度有较大的 负 权重,那么 PC1 可能主要代表了花瓣大小与萼片宽度的对比这个综合特征。
- 对于 PC2 ,权重模式不同,它可能代表了另一种特征组合。通过分析这些权重,我们可以为抽象的主成分赋予一些实际的生物学或业务含义。
总结与实践练习
关键要点总结
- PCA 是什么 :一种无监督的线性降维方法,通过寻找数据方差最大的正交方向(主成分)来重新表述数据。
- 核心步骤 :标准化 -> 计算协方差矩阵 -> 计算特征值与特征向量 -> 选择主成分 -> 数据投影。
-
重要概念
:
- 主成分 :新的、不相关的特征轴。
- 方差解释率 :衡量每个主成分重要性的指标。
- 载荷 :连接原始特征与主成分的桥梁,用于解释主成分的意义。
- 主要应用 :数据可视化、去除噪声和冗余、作为其他模型(如分类、回归)的预处理步骤以加速训练。
动手练习
为了巩固知识,请尝试完成以下练习:
练习1:探索不同数据集
尝试对
scikit-learn
中的其他数据集(如
digits
手写数字数据集或
wine
葡萄酒数据集)进行 PCA 可视化。观察降维后的图像是否还能保留不同类别之间的区分度。
# 提示:加载葡萄酒数据集fromsklearn.datasetsimportload_winewine=load_wine()# ... 重复PCA流程
练习2:三维可视化
将鸢尾花数据降至3维,并使用
mpl_toolkits.mplot3d
库进行三维散点图绘制。看看增加一个维度后,Versicolor和Virginica的重叠是否减少。
frommpl_toolkits.mplot3dimportAxes3Dpca3=PCA(n_components=3)X_pca3=pca3.fit_transform(X_scaled)# ... 创建3D图形进行绘制