查看全课大纲(第 27 / 35 节)

案例实操:特征降维

约 7 分钟

小象实战讲义 · 特征工程精讲与实践

在特征工程流程中,当我们面对高维数据、特征间存在多重共线性,或者希望将数据压缩以进行可视化时,数据降维技术就变得至关重要。本节我们将通过经典的鸢尾花(Iris)数据集,动手实践三种主流的降维方法:主成分分析(PCA)、线性判别分析(LDA)和 t-SNE,直观感受降维的效果与差异。

💡 核心导读

  • 降维目的:压缩数据维度、缓解多重共线性、便于数据可视化。
  • PCA(主成分分析):无监督线性降维,寻找方差最大的正交主成分。
  • LDA(线性判别分析):有监督线性降维,最大化类间距离、最小化类内距离。
  • t-SNE(t分布随机近邻嵌入):非线性降维,擅长保持局部结构,常用于可视化。
  • 工程实践要点:降维前通常需标准化、降维后特征可解释性变差。

一、准备数据:鸢尾花数据集

我们使用 sklearn 内置的鸢尾花数据集。它包含 150 个样本,每个样本有 4 个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度)和 1 个标签(3 种鸢尾花类别)。

# 导入基础库
import numpy as np
import pandas as pd
from sklearn import datasets

# 加载鸢尾花数据集
iris = datasets.load_iris()
# 特征数据 (150个样本, 4个特征)
X_raw = iris.data
# 标签数据 (3种类别: 0, 1, 2)
y = iris.target
# 特征名称
feature_names = iris.feature_names
# 类别名称
target_names = iris.target_names

print("【数据集概览】")
print("特征数据形状 (样本数, 特征数):", X_raw.shape)
print("特征名称:", feature_names)
print("标签类别:", target_names)
print("前5个样本的特征数据:\n", X_raw[:5])
print("前5个样本的标签:", y[:5])
【数据集概览】
特征数据形状 (样本数, 特征数): (150, 4)
特征名称: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
标签类别: ['setosa' 'versicolor' 'virginica']
前5个样本的特征数据:
 [[5.1 3.5 1.4 0.2]
 [4.9 3.  1.4 0.2]
 [4.7 3.2 1.3 0.2]
 [4.6 3.1 1.5 0.2]
 [5.  3.6 1.4 0.2]]
前5个样本的标签: [0 0 0 0 0]

二、主成分分析(PCA)降维

PCA 是一种无监督的线性降维方法。它通过线性变换,将原始数据映射到一组新的正交特征(主成分)上,这些主成分按照方差从大到小排序。我们通常保留前 k 个主成分,以捕获数据中的主要变异。

关键步骤:

  1. 对数据进行标准化(消除量纲影响)。
  2. 计算数据的协方差矩阵。
  3. 计算协方差矩阵的特征值和特征向量。
  4. 将特征值从大到小排序,选择前 k 个特征向量构成投影矩阵。
  5. 将原始数据投影到新的 k 维空间。
import numpy as np
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler

iris = load_iris()
X_raw = iris.data
y = iris.target

from sklearn.decomposition import PCA

# 1. 数据标准化(重要步骤)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_raw)

# 2. PCA降维至2维和3维
pca_2d = PCA(n_components=2)
X_pca_2d = pca_2d.fit_transform(X_scaled)

pca_3d = PCA(n_components=3)
X_pca_3d = pca_3d.fit_transform(X_scaled)

print("【PCA 降维结果】")
print("标准化后数据形状:", X_scaled.shape)
print("PCA 2维降维后数据形状:", X_pca_2d.shape)
print("PCA 2维 - 各主成分解释的方差比例:", pca_2d.explained_variance_ratio_)
print("PCA 2维 - 累计解释方差比例:", sum(pca_2d.explained_variance_ratio_))
print("PCA 3维 - 各主成分解释的方差比例:", pca_3d.explained_variance_ratio_)
print("PCA 3维 - 累计解释方差比例:", sum(pca_3d.explained_variance_ratio_))
print("前5个样本的2维PCA结果:\n", X_pca_2d[:5])
【PCA 降维结果】
标准化后数据形状: (150, 4)
PCA 2维降维后数据形状: (150, 2)
PCA 2维 - 各主成分解释的方差比例: [0.72962445 0.22850762]
PCA 2维 - 累计解释方差比例: 0.9581320720000166
PCA 3维 - 各主成分解释的方差比例: [0.72962445 0.22850762 0.03668922]
PCA 3维 - 累计解释方差比例: 0.9948212908928453
前5个样本的2维PCA结果:
 [[-2.26470281  0.4800266 ]
 [-2.08096115 -0.67413356]
 [-2.36422905 -0.34190802]
 [-2.29938422 -0.59739451]
 [-2.38984217  0.64683538]]

解读:

  • 前两个主成分累计解释了约 95.8% 的方差,这意味着我们仅用两个维度就保留了原始四维数据中绝大部分的信息。
  • 前三个主成分累计解释了约 99.5% 的方差,几乎保留了全部信息。
  • 降维后的数据(X_pca_2d)是原始数据在主成分方向上的投影坐标。

三、线性判别分析(LDA)降维

LDA 是一种有监督的线性降维方法。它的目标是找到一个投影方向,使得同类样本的投影点尽可能接近(类内散度小),不同类样本的投影点尽可能远离(类间散度大)。因此,LDA 在拟合时需要用到标签信息。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler

iris = load_iris()
X_raw = iris.data
X_scaled = StandardScaler().fit_transform(X_raw)
y = iris.target

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

# LDA降维至2维(对于3类问题,最多可降至2维)
lda = LinearDiscriminantAnalysis(n_components=2)
# 注意:LDA的fit方法需要特征X和标签y
lda.fit(X_scaled, y)
X_lda_2d = lda.transform(X_scaled)

print("【LDA 降维结果】")
print("LDA 2维降维后数据形状:", X_lda_2d.shape)
print("LDA解释的方差比例(判别能力):", lda.explained_variance_ratio_)
print("总解释方差比例:", sum(lda.explained_variance_ratio_))
print("前5个样本的2维LDA结果:\n", X_lda_2d[:5])
【LDA 降维结果】
LDA 2维降维后数据形状: (150, 2)
LDA解释的方差比例(判别能力): [0.9912126 0.0087874]
总解释方差比例: 0.9999999999999999
前5个样本的2维LDA结果:
 [[ 8.14364756 -0.30347066]
 [ 7.20106204  0.79464703]
 [ 7.56586878  0.26807882]
 [ 6.88237189  0.67743968]
 [ 8.21487296 -0.51968563]]

解读:

  • LDA 的第一个线性判别方向(LDA1)就解释了 99.1% 的判别信息,说明在这个方向上,不同类别已经被很好地分开了。
  • LDA 降维后的数据(X_lda_2d)直接服务于分类任务,其类间区分度通常比 PCA 更明显。

四、t-SNE 非线性降维

t-SNE 是一种非线性降维方法,特别擅长在低维(通常是2维或3维)空间中保持高维数据的局部结构。它通过将高维空间中的相似性(用高斯分布表示)与低维空间中的相似性(用 t 分布表示)进行匹配来实现降维。t-SNE 常用于数据可视化,但其计算成本较高。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler

iris = load_iris()
X_raw = iris.data
y = iris.target
X_scaled = StandardScaler().fit_transform(X_raw)

from sklearn.manifold import TSNE

# t-SNE降维至2维
# 注意:sklearn 1.9.1 中参数为 max_iter,不再是 n_iter
tsne = TSNE(n_components=2, max_iter=1000, random_state=42, perplexity=30)
# t-SNE通常直接对缩放后的数据拟合变换
X_tsne_2d = tsne.fit_transform(X_scaled)

print("【t-SNE 降维结果】")
print("t-SNE 2维降维后数据形状:", X_tsne_2d.shape)
print("前5个样本的2维t-SNE结果:\n", X_tsne_2d[:5])
【t-SNE 降维结果】
t-SNE 2维降维后数据形状: (150, 2)
前5个样本的2维t-SNE结果:
 [[-24.310734   -2.1122737]
 [-20.536928   -1.3836074]
 [-21.545553   -2.4164944]
 [-20.773043   -2.4609888]
 [-24.798649   -2.6877975]]

解读:

  • t-SNE 的输出没有像 PCA 那样的“解释方差比例”概念,它的目标是保持数据点之间的相对距离关系。
  • 从结果可以看出,t-SNE 产生的坐标值与 PCA/LDA 有显著不同,它更关注于局部邻域的结构。

五、方法对比与工程思考

通过以上实践,我们可以总结出三种降维方法的特点:

方法类型是否需要标签主要目标优点缺点
PCA线性、无监督否最大化方差,保留全局信息计算高效,无需标签,能消除特征共线性主成分是原始特征的线性组合、失去直接物理含义;对非线性结构效果不佳
LDA线性、有监督是最大化类间区分度对分类任务友好,降维后特征判别力强只能用于有标签数据,最多降至(类别数-1)维
t-SNE非线性、无监督否保持局部相似性结构可视化效果好,能揭示复杂流形结构计算慢,结果不稳定(受参数影响大),不适合作为特征输入后续模型

工程实践中的重要提醒:

  1. 标准化先行(对 PCA 是必须):PCA 基于方差,量纲大的特征会主导主成分方向,使用前务必标准化(如 StandardScaler)。LDA 则有所不同——其 Fisher 判别目标对可逆线性变换(如标准化)具有不变性,标准化不是硬性前提(本课 fe_6_1_1 的 LDA 演示就未缩放);但实践中标准化通常仍无害且便于调参。
  2. 可解释性丧失:降维后的特征(主成分、判别式)是原始特征的线性或非线性组合,失去了直接的物理含义。这可能会降低最终模型的可解释性。
  3. 为何降维:不要为了降维而降维。降维通常用于:
    • 可视化:将高维数据降至2D/3D进行观察。
    • 缓解共线性:当特征间高度相关时,PCA可以提取不相关的成分。
    • 数据压缩:减少存储和计算开销。
    • 噪声过滤:舍弃方差小的成分可能同时滤除噪声。
  4. 特征选择 vs. 特征降维:特征选择是保留原始特征的一个子集,特征可解释性得以保留;特征降维是创建全新的综合特征,可能丢失可解释性但能更紧凑地表示信息。

📝 动手练一练

  1. 概念辨析:假设你有一个包含 100 个特征的数据集,并且知道其中很多特征是高度相关的。你的目标是构建一个可解释性强的预测模型。在这种情况下,你更倾向于使用特征选择还是 PCA 降维?为什么?
👉 点击查看参考答案

参考答案:更倾向于使用特征选择。

  • 原因:PCA 降维产生的新特征(主成分)是原始特征的线性组合,失去了直接的业务含义,会严重削弱模型的可解释性。而特征选择是从原始特征中挑选出一个子集,这些特征本身具有明确的业务含义(如“用户年龄”、“交易金额”),便于业务人员理解和信任模型的决策。对于高度相关的特征,可以通过特征选择方法(如基于树模型的特征重要性)或过滤法(如去除方差膨胀因子 VIF 过高的特征)来筛选,既能缓解共线性,又能保持可解释性。
  1. 代码实践:在 PCA 实操部分,我们使用了 StandardScaler 进行标准化。如果不进行标准化,直接对原始数据 X_raw 进行 PCA 降维,第一个主成分解释的方差比例会发生怎样的变化?请通过代码验证你的猜想。
👉 点击查看参考答案

参考答案:如果不进行标准化,方差大的特征(在 Iris 数据集中,花瓣长度的取值范围与方差都是四个特征中最大的)会主导主成分的方向,导致第一个主成分几乎完全由这类特征决定,其解释的方差比例会异常高,但可能并未捕获数据中最有意义的变化模式。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler

iris = load_iris()
X_raw = iris.data
X_scaled = StandardScaler().fit_transform(X_raw)
y = iris.target

from sklearn.decomposition import PCA

# 对原始数据(未标准化)进行PCA降维
pca_raw = PCA(n_components=2)
X_pca_raw = pca_raw.fit_transform(X_raw)  # 使用 X_raw

print("【PCA 2维 - 原始数据(未标准化)】")
print("各主成分解释的方差比例:", pca_raw.explained_variance_ratio_)
print("第一个主成分解释的方差比例:", pca_raw.explained_variance_ratio_[0])
print("总解释方差比例:", sum(pca_raw.explained_variance_ratio_))
【PCA 2维 - 原始数据(未标准化)】
各主成分解释的方差比例: [0.92461872 0.05306648]
第一个主成分解释的方差比例: 0.9246187232017302
总解释方差比例: 0.9776852063187963

对比与结论:

  • 标准化后:第一个主成分解释方差比例约为 0.730。
  • 未标准化:第一个主成分解释方差比例高达 0.925。
  • 这说明在原始数据中,由于特征量纲差异,第一个主成分几乎被花瓣尺寸相关的特征所垄断。标准化后,各特征被平等对待,主成分能更均衡地反映所有特征的综合变化,其方差分布更合理。因此,PCA 前进行标准化是标准做法。

本章小结

本节我们深入实践了特征工程中数据降维的核心技术。我们以鸢尾花数据集为例,逐步实现了 PCA、LDA 和 t-SNE 三种降维方法,并对比了它们的特点与适用场景。

📋 行动清单

  • 跑通代码:在本地或在线环境中完整运行本节的所有代码,观察不同降维方法输出的数据形态。
  • 理解差异:清晰说出 PCA、LDA 和 t-SNE 在原理、输入要求和输出目标上的核心区别。
  • 建立直觉:记住降维后特征可解释性变差这一关键点,在需要向业务方解释模型的场景中谨慎使用降维技术。

降维是处理高维数据、提取核心信息的强大工具。掌握其原理并了解其局限性,能帮助你在实际项目中更加游刃有余地应对“维度灾难”。

—— 小象教研组