4、PCA实战(Python):使用sklearn进行PCA降维、explained_variance_ratio_的解读、二维可视化散点图
好,咱们直接进入正题。
前面聊了那么多PCA的理论,什么协方差矩阵、特征向量、投影空间……说实话,光看公式容易晕。我当年学的时候也是,推导了一遍觉得懂了,一上手写代码还是懵。
所以这一节,咱们直接撸代码。用Python的sklearn库,把PCA跑一遍。你会发现,其实核心代码就那么几行。
4.1 准备工作:导入库与数据集
我个人习惯,做任何数据分析之前,先把环境理清楚。这里我们用经典的鸢尾花(Iris)数据集。它只有4个特征,非常适合用来演示降维。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
# 加载数据
iris = load_iris()
X = iris.data
y = iris.target
feature_names = iris.feature_names
print("原始数据形状:", X.shape)
print("特征名称:", feature_names)
输出结果:
原始数据形状: (150, 4)
特征名称: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
嗯,150个样本,4个特征。目标是把这4维降到2维,方便可视化。
4.2 数据标准化
标准化这一步,说白了就是把每个特征变成均值为0、标准差为1的分布。用StandardScaler搞定。
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print("标准化后数据均值:", np.mean(X_scaled, axis=0).round(6))
print("标准化后数据标准差:", np.std(X_scaled, axis=0).round(6))
输出:
标准化后数据均值: [ 0. -0. 0. 0.]
标准化后数据标准差: [1. 1. 1. 1.]
你看,均值接近0,标准差为1。完美。
4.3 执行PCA降维
核心代码来了。我们指定n_components=2,把4维降到2维。
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
print("降维后数据形状:", X_pca.shape)
输出:
降维后数据形状: (150, 2)
就这么简单。现在每个样本只有2个特征了,可以直接画散点图。
4.4 explained_variance_ratio_ 的解读
这里有个非常重要的属性——explained_variance_ratio_。它告诉你每个主成分“解释”了多少原始数据的方差。
print("各主成分解释方差比例:", pca.explained_variance_ratio_)
print("累计解释方差比例:", np.sum(pca.explained_variance_ratio_))
输出:
各主成分解释方差比例: [0.72962445 0.22850762]
累计解释方差比例: 0.95813207
什么意思?
- 第一个主成分(PC1)解释了约73%的方差
- 第二个主成分(PC2)解释了约23%的方差
- 两者加起来,保留了原始数据约96%的信息
你想想看,从4维降到2维,信息损失只有4%左右。这就是PCA的厉害之处。
explained_variance_ratio_ 的值越大,说明该主成分越重要。如果前几个主成分的累计比例超过85%,通常就可以认为降维效果不错。
我在项目中遇到过,有时候前两个主成分只能解释60%的方差,那就得考虑保留3个或4个主成分了。别死磕2维。
4.5 二维可视化散点图
好,数据降完了,咱们画个图看看效果。
plt.figure(figsize=(10, 6))
colors = ['navy', 'turquoise', 'darkorange']
target_names = iris.target_names
for color, i, target_name in zip(colors, [0, 1, 2], target_names):
plt.scatter(X_pca[y == i, 0], X_pca[y == i, 1],
color=color, alpha=0.8, lw=2,
label=target_name)
plt.xlabel('第一主成分 (PC1) - 解释方差 {:.2f}%'.format(pca.explained_variance_ratio_[0]*100))
plt.ylabel('第二主成分 (PC2) - 解释方差 {:.2f}%'.format(pca.explained_variance_ratio_[1]*100))
plt.title('PCA降维后的鸢尾花数据二维可视化')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
画出来的图,三个类别在二维平面上分得清清楚楚。setosa那一类完全独立,versicolor和virginica虽然有点重叠,但整体边界还是很明显的。
如果你发现降维后的图分类效果不好,别急着怀疑PCA。先检查一下标准化有没有做,再试试保留更多主成分。我习惯先画一个explained_variance_ratio_的累积曲线图,看看拐点在哪里。
4.6 完整代码汇总
为了方便你直接复制运行,我把完整代码贴出来:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
# 1. 加载数据
iris = load_iris()
X = iris.data
y = iris.target
# 2. 标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 3. PCA降维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
# 4. 输出解释方差
print("解释方差比例:", pca.explained_variance_ratio_)
print("累计解释方差:", np.sum(pca.explained_variance_ratio_))
# 5. 可视化
plt.figure(figsize=(10, 6))
colors = ['navy', 'turquoise', 'darkorange']
target_names = iris.target_names
for color, i, target_name in zip(colors, [0, 1, 2], target_names):
plt.scatter(X_pca[y == i, 0], X_pca[y == i, 1],
color=color, alpha=0.8, lw=2,
label=target_name)
plt.xlabel('PC1 ({:.2f}%)'.format(pca.explained_variance_ratio_[0]*100))
plt.ylabel('PC2 ({:.2f}%)'.format(pca.explained_variance_ratio_[1]*100))
plt.title('PCA降维可视化')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
4.7 避坑指南
最后,分享几个我踩过的坑:
- 忘记标准化:这是最常见的错误。不标准化的话,PCA会优先保留量纲大的特征,结果往往很离谱。
- 只看累计方差:累计方差高不代表降维效果好。有时候90%的方差被第一个主成分占了,剩下10%里可能藏着关键信息。我建议至少保留2-3个主成分看看。
- 过度解读主成分:降维后的坐标轴(PC1、PC2)是原始特征的线性组合,很难直接解释成某个具体特征。别硬解释。
嗯,这一节就到这儿。代码不多,但每一步都很关键。你动手跑一遍,感受一下从4维到2维的变化,比看十遍理论都管用。