降维技术 #
概述 #
降维是将高维数据映射到低维空间的技术,用于数据可视化、特征压缩和去除噪声。
降维方法分类 #
| 类型 | 方法 | 特点 |
|---|---|---|
| 线性降维 | 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