降维Skill DimensionalityReduction

降维技术通过减少特征数量来保留重要信息,提高模型效率,并使高维数据的可视化成为可能。关键词:降维、PCA、t-SNE、特征选择、数据可视化。

数据分析 0 次安装 0 次浏览 更新于 3/3/2026

降维

概览

降维技术通过减少特征数量来保留重要信息,提高模型效率,并使高维数据的可视化成为可能。

使用场景

  • 高维数据集,特征众多
  • 在2D或3D中可视化复杂数据集
  • 降低计算复杂性和训练时间
  • 移除冗余或高度相关的特征
  • 防止机器学习模型过拟合
  • 在聚类或分类之前预处理数据

技术

  • PCA:主成分分析
  • t-SNE:t分布随机邻域嵌入
  • UMAP:均匀流形近似和投影
  • 特征选择:选择重要特征
  • 特征提取:创建新特征

优点

  • 降低计算复杂性
  • 移除噪声和冗余
  • 提高模型泛化能力
  • 使可视化成为可能
  • 防止维度灾难

Python实现

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA, TruncatedSVD, FactorAnalysis
from sklearn.manifold import TSNE, MDS
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectKBest, f_classif, mutual_info_classif
import seaborn as sns

# 加载数据
iris = load_iris()
X = iris.data
y = iris.target
feature_names = iris.feature_names

# 标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# PCA
pca = PCA()
pca.fit(X_scaled)

# 解释方差
explained_variance = np.cumsum(pca.explained_variance_ratio_)
print("解释方差比率按成分:")
print(pca.explained_variance_ratio_)
print(f"累积方差(前2个): {explained_variance[1]:.4f}")

# 折线图
fig, axes = plt.subplots(1, 2, figsize=(14, 4))

axes[0].plot(range(1, len(pca.explained_variance_ratio_) + 1),
             pca.explained_variance_ratio_, 'bo-')
axes[0].set_xlabel('主成分')
axes[0].set_ylabel('解释方差比率')
axes[0].set_title('折线图')
axes[0].grid(True, alpha=0.3)

axes[1].plot(range(1, len(explained_variance) + 1),
             explained_variance, 'go-')
axes[1].axhline(y=0.95, color='r', linestyle='--', label='95%方差')
axes[1].set_xlabel('成分数量')
axes[1].set_ylabel('累积解释方差')
axes[1].set_title('累积解释方差')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 2成分PCA
pca_2d = PCA(n_components=2)
X_pca_2d = pca_2d.fit_transform(X_scaled)

# 3成分PCA
pca_3d = PCA(n_components=3)
X_pca_3d = pca_3d.fit_transform(X_scaled)

# PCA可视化
fig = plt.figure(figsize=(14, 5))

# 2D PCA
ax1 = fig.add_subplot(131)
scatter = ax1.scatter(X_pca_2d[:, 0], X_pca_2d[:, 1], c=y, cmap='viridis', alpha=0.6)
ax1.set_xlabel(f'PC1 ({pca_2d.explained_variance_ratio_[0]:.2%})')
ax1.set_ylabel(f'PC2 ({pca_2d.explained_variance_ratio_[1]:.2%})')
ax1.set_title('PCA 2D')
plt.colorbar(scatter, ax=ax1)

# 3D PCA
ax2 = fig.add_subplot(132, projection='3d')
scatter = ax2.scatter(X_pca_3d[:, 0], X_pca_3d[:, 1], X_pca_3d[:, 2],
                      c=y, cmap='viridis', alpha=0.6)
ax2.set_xlabel(f'PC1 ({pca_3d.explained_variance_ratio_[0]:.2%})')
ax2.set_ylabel(f'PC2 ({pca_3d.explained_variance_ratio_[1]:.2%})')
ax2.set_zlabel(f'PC3 ({pca_3d.explained_variance_ratio_[2]:.2%})')
ax2.set_title('PCA 3D')

# 加载图
ax3 = fig.add_subplot(133)
loadings = pca_2d.components_.T
for i, feature in enumerate(feature_names):
    ax3.arrow(0, 0, loadings[i, 0], loadings[i, 1],
             head_width=0.05, head_length=0.05, fc='blue', ec='blue')
    ax3.text(loadings[i, 0]*1.15, loadings[i, 1]*1.15, feature, fontsize=10)
ax3.set_xlim(-1, 1)
ax3.set_ylim(-1, 1)
ax3.set_xlabel(f'PC1 ({pca_2d.explained_variance_ratio_[0]:.2%})')
ax3.set_ylabel(f'PC2 ({pca_2d.explained_variance_ratio_[1]:.2%})')
ax3.set_title('PCA 加载')
ax3.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# t-SNE可视化
tsne = TSNE(n_components=2, random_state=42, perplexity=30)
X_tsne = tsne.fit_transform(X_scaled)

plt.figure(figsize=(8, 6))
scatter = plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='viridis', alpha=0.6)
plt.xlabel('t-SNE 维度1')
plt.ylabel('t-SNE 维度2')
plt.title('t-SNE 可视化')
plt.colorbar(scatter, label='类别')
plt.show()

# MDS可视化
mds = MDS(n_components=2, random_state=42)
X_mds = mds.fit_transform(X_scaled)

plt.figure(figsize=(8, 6))
scatter = plt.scatter(X_mds[:, 0], X_mds[:, 1], c=y, cmap='viridis', alpha=0.6)
plt.xlabel('MDS 维度1')
plt.ylabel('MDS 维度2')
plt.title('MDS 可视化')
plt.colorbar(scatter, label='类别')
plt.show()

# 特征选择 - SelectKBest
selector = SelectKBest(score_func=f_classif, k=2)
X_selected = selector.fit_transform(X, y)
selected_features = np.array(feature_names)[selector.get_support()]
scores = selector.scores_

feature_scores = pd.DataFrame({
    '特征': feature_names,
    '分数': scores
}).sort_values('分数', ascending=False)

print("
特征选择(F检验):")
print(feature_scores)

plt.figure(figsize=(10, 5))
plt.barh(feature_scores['特征'], feature_scores['分数'])
plt.xlabel('F检验分数')
plt.title('特征重要性(SelectKBest)')
plt.tight_layout()
plt.show()

# 互信息
selector_mi = SelectKBest(score_func=mutual_info_classif, k=2)
X_selected_mi = selector_mi.fit_transform(X, y)
scores_mi = selector_mi.scores_

feature_scores_mi = pd.DataFrame({
    '特征': feature_names,
    '分数': scores_mi
}).sort_values('分数', ascending=False)

print("
特征选择(互信息):")
print(feature_scores_mi)

# 基于树的特征重要性
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)
importances = rf.feature_importances_

feature_importance = pd.DataFrame({
    '特征': feature_names,
    '重要性': importances
}).sort_values('重要性', ascending=False)

print("
特征重要性(随机森林):")
print(feature_importance)

plt.figure(figsize=(10, 5))
plt.barh(feature_importance['特征'], feature_importance['重要性'])
plt.xlabel('重要性')
plt.title('特征重要性(随机森林)')
plt.tight_layout()
plt.show()

# 因子分析
fa = FactorAnalysis(n_components=2, random_state=42)
X_fa = fa.fit_transform(X_scaled)

plt.figure(figsize=(8, 6))
scatter = plt.scatter(X_fa[:, 0], X_fa[:, 1], c=y, cmap='viridis', alpha=0.6)
plt.xlabel('因子1')
plt.ylabel('因子2')
plt.title('因子分析')
plt.colorbar(scatter, label='类别')
plt.show()

# 模型性能比较
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression

models = {
    '原始特征': X_scaled,
    'PCA (2)': X_pca_2d,
    'PCA (3)': X_pca_3d,
    't-SNE': X_tsne,
    '选择(2个最佳)': X_selected,
}

scores = {}
for name, X_reduced in models.items():
    clf = LogisticRegression(max_iter=200)
    cv_scores = cross_val_score(clf, X_reduced, y, cv=5, scoring='accuracy')
    scores[name] = {
        '平均准确率': cv_scores.mean(),
        '标准差': cv_scores.std(),
        '特征': X_reduced.shape[1],
    }

scores_df = pd.DataFrame(scores).T
print("
不同维度下的模型性能:")
print(scores_df)

算法比较

  • PCA:线性,快速,可解释
  • t-SNE:非线性,可视化效果好,计算成本高
  • UMAP:非线性,保持局部/全局结构
  • 特征选择:保持可解释性
  • 因子分析:统计方法

选择成分数量

  • 解释方差:保留95%的方差
  • 肘部法则:在折线图中寻找“肘部”
  • 交叉验证:针对下游任务进行优化

交付物

  • 折线图和累积方差
  • 2D/3D可视化
  • PCA加载解释
  • 特征重要性排名
  • 模型性能比较
  • 成分解释