降维技术 #

概述 #

降维是将高维数据映射到低维空间的技术,用于数据可视化、特征压缩和去除噪声。

降维方法分类 #

类型 方法 特点
线性降维 PCA, LDA 计算快,可解释
非线性降维 t-SNE, UMAP 保持局部结构
矩阵分解 NMF, SVD 可解释性强

为什么需要降维? #

原因 描述
维度灾难 高维数据稀疏,模型效果下降
可视化 人类只能理解 2D/3D 数据
计算效率 减少特征数量,加速训练
去噪 去除冗余和噪声特征

PCA(主成分分析) #

基本使用 #

python
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt

iris = load_iris()
X = iris.data

pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)

plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target, cmap='viridis')
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.title('PCA: Iris Dataset')

参数说明 #

参数 描述
n_components 保留的主成分数量
svd_solver SVD 求解器
whiten 是否白化
python
pca = PCA(n_components=2, svd_solver='auto', whiten=False)

解释方差 #

python
pca = PCA()
pca.fit(X)

print(f"解释方差比: {pca.explained_variance_ratio_}")
print(f"累计解释方差: {np.cumsum(pca.explained_variance_ratio_)}")

plt.bar(range(len(pca.explained_variance_ratio_)), pca.explained_variance_ratio_)
plt.xlabel('Principal Component')
plt.ylabel('Explained Variance Ratio')

选择主成分数量 #

python
pca = PCA(n_components=0.95)
X_pca = pca.fit_transform(X)

print(f"保留 95% 方差需要 {pca.n_components_} 个主成分")

白化 #

python
pca_whiten = PCA(n_components=2, whiten=True)
X_whitened = pca_whiten.fit_transform(X)

print(f"白化后方差: {X_whitened.var(axis=0)}")

增量 PCA #

python
from sklearn.decomposition import IncrementalPCA

ipca = IncrementalPCA(n_components=2, batch_size=10)

for batch in np.array_split(X, 10):
    ipca.partial_fit(batch)

X_ipca = ipca.transform(X)

稀疏 PCA #

python
from sklearn.decomposition import SparsePCA

spca = SparsePCA(n_components=2, alpha=1, random_state=42)
X_spca = spca.fit_transform(X)

LDA(线性判别分析) #

基本使用 #

python
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, iris.target)

plt.scatter(X_lda[:, 0], X_lda[:, 1], c=iris.target, cmap='viridis')
plt.xlabel('LD1')
plt.ylabel('LD2')
plt.title('LDA: Iris Dataset')

PCA vs LDA #

特性 PCA LDA
类型 无监督 有监督
目标 最大方差 最大类间距离
最大维度 n_features n_classes - 1
python
fig, axes = plt.subplots(1, 2, figsize=(12, 5))

pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
axes[0].scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target, cmap='viridis')
axes[0].set_title('PCA')

lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, iris.target)
axes[1].scatter(X_lda[:, 0], X_lda[:, 1], c=iris.target, cmap='viridis')
axes[1].set_title('LDA')

t-SNE #

基本使用 #

python
from sklearn.manifold import TSNE

tsne = TSNE(
    n_components=2,
    perplexity=30,
    learning_rate=200,
    random_state=42
)
X_tsne = tsne.fit_transform(X)

plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=iris.target, cmap='viridis')
plt.title('t-SNE: Iris Dataset')

重要参数 #

参数 描述 默认值
n_components 目标维度 2
perplexity 困惑度 30
learning_rate 学习率 200
n_iter 迭代次数 1000
metric 距离度量 ‘euclidean’

perplexity 影响 #

python
perplexities = [5, 30, 50, 100]

fig, axes = plt.subplots(2, 2, figsize=(12, 10))

for ax, perp in zip(axes.ravel(), perplexities):
    tsne = TSNE(n_components=2, perplexity=perp, random_state=42)
    X_tsne = tsne.fit_transform(X)
    ax.scatter(X_tsne[:, 0], X_tsne[:, 1], c=iris.target, cmap='viridis')
    ax.set_title(f'perplexity={perp}')

学习率影响 #

python
learning_rates = [10, 100, 200, 500]

for lr in learning_rates:
    tsne = TSNE(n_components=2, learning_rate=lr, random_state=42)
    X_tsne = tsne.fit_transform(X)

MDS(多维缩放) #

基本使用 #

python
from sklearn.manifold import MDS

mds = MDS(n_components=2, random_state=42)
X_mds = mds.fit_transform(X)

plt.scatter(X_mds[:, 0], X_mds[:, 1], c=iris.target, cmap='viridis')
plt.title('MDS: Iris Dataset')

Isomap #

基本使用 #

python
from sklearn.manifold import Isomap

isomap = Isomap(n_components=2, n_neighbors=5)
X_isomap = isomap.fit_transform(X)

plt.scatter(X_isomap[:, 0], X_isomap[:, 1], c=iris.target, cmap='viridis')
plt.title('Isomap: Iris Dataset')

Locally Linear Embedding #

基本使用 #

python
from sklearn.manifold import LocallyLinearEmbedding

lle = LocallyLinearEmbedding(
    n_components=2,
    n_neighbors=10,
    random_state=42
)
X_lle = lle.fit_transform(X)

plt.scatter(X_lle[:, 0], X_lle[:, 1], c=iris.target, cmap='viridis')
plt.title('LLE: Iris Dataset')

NMF(非负矩阵分解) #

基本使用 #

python
from sklearn.decomposition import NMF

nmf = NMF(n_components=2, random_state=42)
X_nmf = nmf.fit_transform(X)

plt.scatter(X_nmf[:, 0], X_nmf[:, 1], c=iris.target, cmap='viridis')
plt.title('NMF: Iris Dataset')

特点 #

特性 描述
非负约束 分解结果非负
可解释性 部分加性表示
应用 文本挖掘、图像处理

TruncatedSVD #

基本使用 #

python
from sklearn.decomposition import TruncatedSVD

svd = TruncatedSVD(n_components=2, random_state=42)
X_svd = svd.fit_transform(X)

print(f"解释方差比: {svd.explained_variance_ratio_}")

适用于稀疏数据 #

python
from scipy.sparse import csr_matrix

X_sparse = csr_matrix(X)
svd = TruncatedSVD(n_components=2)
X_svd = svd.fit_transform(X_sparse)

字典学习 #

基本使用 #

python
from sklearn.decomposition import DictionaryLearning

dl = DictionaryLearning(n_components=2, random_state=42)
X_dl = dl.fit_transform(X)

因子分析 #

基本使用 #

python
from sklearn.decomposition import FactorAnalysis

fa = FactorAnalysis(n_components=2, random_state=42)
X_fa = fa.fit_transform(X)

核 PCA #

基本使用 #

python
from sklearn.decomposition import KernelPCA

kpca = KernelPCA(
    n_components=2,
    kernel='rbf',
    gamma=10,
    random_state=42
)
X_kpca = kpca.fit_transform(X)

plt.scatter(X_kpca[:, 0], X_kpca[:, 1], c=iris.target, cmap='viridis')
plt.title('Kernel PCA (RBF)')

核函数选择 #

python
kernels = ['linear', 'poly', 'rbf', 'sigmoid']

fig, axes = plt.subplots(2, 2, figsize=(12, 10))

for ax, kernel in zip(axes.ravel(), kernels):
    kpca = KernelPCA(n_components=2, kernel=kernel, random_state=42)
    X_kpca = kpca.fit_transform(X)
    ax.scatter(X_kpca[:, 0], X_kpca[:, 1], c=iris.target, cmap='viridis')
    ax.set_title(f'Kernel: {kernel}')

方法对比 #

可视化对比 #

python
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE, MDS, Isomap
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

methods = {
    'PCA': PCA(n_components=2),
    'LDA': LinearDiscriminantAnalysis(n_components=2),
    't-SNE': TSNE(n_components=2, random_state=42),
    'MDS': MDS(n_components=2, random_state=42),
    'Isomap': Isomap(n_components=2),
    'Kernel PCA': KernelPCA(n_components=2, kernel='rbf')
}

fig, axes = plt.subplots(2, 3, figsize=(15, 10))

for ax, (name, method) in zip(axes.ravel(), methods.items()):
    if name == 'LDA':
        X_transformed = method.fit_transform(X, iris.target)
    else:
        X_transformed = method.fit_transform(X)
    ax.scatter(X_transformed[:, 0], X_transformed[:, 1], c=iris.target, cmap='viridis')
    ax.set_title(name)

重构误差 #

PCA 重构 #

python
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
X_reconstructed = pca.inverse_transform(X_pca)

reconstruction_error = np.mean((X - X_reconstructed) ** 2)
print(f"重构误差: {reconstruction_error:.4f}")

不同维度重构误差 #

python
errors = []
components_range = range(1, X.shape[1] + 1)

for n in components_range:
    pca = PCA(n_components=n)
    X_pca = pca.fit_transform(X)
    X_rec = pca.inverse_transform(X_pca)
    errors.append(np.mean((X - X_rec) ** 2))

plt.plot(components_range, errors, 'bo-')
plt.xlabel('Number of Components')
plt.ylabel('Reconstruction Error')

实战示例 #

手写数字可视化 #

python
from sklearn.datasets import load_digits

digits = load_digits()
X, y = digits.data, digits.target

tsne = TSNE(n_components=2, random_state=42)
X_tsne = tsne.fit_transform(X)

plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='tab10')
plt.colorbar(scatter)
plt.title('t-SNE: Handwritten Digits')

人脸特征提取 #

python
from sklearn.datasets import fetch_lfw_people

lfw = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
X = lfw.data

pca = PCA(n_components=100, whiten=True, random_state=42)
X_pca = pca.fit_transform(X)

fig, axes = plt.subplots(3, 5, figsize=(12, 8))
for i, ax in enumerate(axes.ravel()):
    ax.imshow(pca.components_[i].reshape(lfw.images[0].shape), cmap='gray')
    ax.set_title(f'PC {i+1}')
    ax.axis('off')

文本降维 #

python
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.datasets import fetch_20newsgroups

newsgroups = fetch_20newsgroups(subset='train', categories=['sci.space', 'rec.autos'])
vectorizer = TfidfVectorizer(max_features=1000)
X = vectorizer.fit_transform(newsgroups.data)

svd = TruncatedSVD(n_components=2, random_state=42)
X_svd = svd.fit_transform(X)

plt.scatter(X_svd[:, 0], X_svd[:, 1], c=newsgroups.target, cmap='viridis', alpha=0.5)
plt.title('TruncatedSVD: Text Data')

最佳实践 #

1. 数据预处理 #

python
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

2. 选择方法 #

目标 推荐方法
特征压缩 PCA
可视化 t-SNE, UMAP
有监督降维 LDA
稀疏数据 TruncatedSVD
非负数据 NMF

3. 保留信息量 #

python
pca = PCA(n_components=0.95)
X_pca = pca.fit_transform(X)
print(f"保留 {pca.n_components_} 个主成分,解释 {sum(pca.explained_variance_ratio_)*100:.1f}% 方差")

4. Pipeline 使用 #

python
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('pca', PCA(n_components=10)),
    ('clf', LogisticRegression())
])

下一步 #

掌握降维技术后,继续学习 异常检测 了解如何识别异常数据!

最后更新:2026-04-04