通透!十大降维算法 最强总计 !!

文摘   2024-07-18 17:26   北京  

哈喽,我是cos大壮!~

在过去一段时间,整理了不少基础模型的详细说明。

但是针对降维算法没有很好的总结,不少同学需要,今天针对降维算法做了很详细的总结,感兴趣的同学可以收藏起来慢慢学习~

首先,咱们进行一个简单的介绍~

降维算法在数据分析和机器学习中至关重要,能够减少数据集的复杂度和噪声,提升模型的效率和准确性。它们帮助识别和保留最具信息量的特征,同时减少计算成本和资源需求,是处理高维数据和解决过拟合问题的关键工具。

老规矩如果大家伙觉得近期文章还不错!欢迎大家点个赞、转个发,文末赠送《机器学习学习小册》
文末可取本文PDF版本~

那么,针对降维算法,我们总结了10个最最常用、最最重要的算法模型,大家可以先看下~

  • 主成分分析(PCA)
  • 线性判别分析(LDA)
  • 奇异值分解(SVD)
  • 独立成分分析(ICA)
  • 非负矩阵分解(NMF)
  • 核PCA(KPCA)
  • t-分布邻域嵌入(t-SNE)
  • 均值散布嵌入(MDS)
  • 局部线性嵌入(LLE)
  • 非线性降维算法(UMAP)

那咱们就从PCA开始,从原理、公式和案例都大家详细聊聊~

1. 主成分分析 (PCA, Principal Component Analysis)

主成分分析(PCA)是最最一种常用的降维技术,通过正交变换将原始数据变换为一组线性不相关的新变量(主成分)。这些新变量按解释的方差大小排序,前几个主成分保留了数据中大部分信息。

核心原理

PCA的核心思想是将数据投影到方差最大的方向上,找到数据的主成分,从而减少特征维度并保留尽可能多的信息。PCA的过程包括数据中心化、计算协方差矩阵、特征值分解和投影。

公式

1. 数据中心化

设有数据矩阵 ,其中  是样本数量, 是特征数量。首先,将数据矩阵进行中心化处理,即减去每个特征的均值。

2. 计算协方差矩阵

协方差矩阵  的计算公式如下:

其中,  是对称矩阵。

3. 特征值分解

对协方差矩阵  进行特征值分解:

其中,  是特征值,  是特征向量。

4. 选取主成分

按照特征值的大小从大到小排列,选择前  个最大的特征值对应的特征向量,构成新的投影矩阵 

5. 数据投影

将原始数据投影到新的低维空间:

公式推导

步骤 1:数据中心化

设数据矩阵 ,每行代表一个样本,每列代表一个特征。中心化处理将每个特征的均值变为0:

中心化后的数据矩阵为:

步骤 2:计算协方差矩阵

中心化后的数据矩阵  的协方差矩阵  计算如下:

协方差矩阵  是一个  的对称矩阵,其中  是特征的数量。

步骤 3:特征值分解

对协方差矩阵  进行特征值分解:

其中, 是特征值, 是对应的特征向量。特征值  代表了投影方向上数据的方差。

步骤 4:选取主成分

将特征值按从大到小排序,选择前  个最大的特征值对应的特征向量构成投影矩阵 

步骤 5:数据投影

将原始数据投影到新的低维空间:

在这种新的低维空间中,数据在每个主成分方向上的方差最大。

案例

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
import seaborn as sns

# 加载数据集
iris = load_iris()
data = iris.data
target = iris.target
target_names = iris.target_names
feature_names = iris.feature_names

# 创建DataFrame
df = pd.DataFrame(data, columns=feature_names)
df['target'] = target

# 进行PCA降维
pca = PCA(n_components=2)
principal_components = pca.fit_transform(data)
principal_df = pd.DataFrame(data=principal_components, columns=['Principal Component 1''Principal Component 2'])
final_df = pd.concat([principal_df, df[['target']]], axis=1)

# 图1: PCA后的散点图
plt.figure(figsize=(106))
sns.scatterplot(data=final_df, x='Principal Component 1', y='Principal Component 2', hue='target', palette='Set1')
plt.title('PCA of Iris Dataset')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.legend(target_names)
plt.show()

# 图2: 原始特征的散点矩阵
sns.pairplot(df, hue='target', palette='Set1', diag_kind='kde')
plt.suptitle('Pairplot of Original Features', y=1.02)
plt.show()

# 图3: PCA后的解释方差比率
plt.figure(figsize=(106))
explained_variance = pca.explained_variance_ratio_
plt.bar(range(len(explained_variance)), explained_variance, alpha=0.7, align='center', label='individual explained variance')
plt.step(range(len(np.cumsum(explained_variance))), np.cumsum(explained_variance), where='mid', linestyle='--', label='cumulative explained variance')
plt.title('Explained Variance by Principal Components')
plt.xlabel('Principal Components')
plt.ylabel('Explained Variance Ratio')
plt.legend(loc='best')
plt.show()

# 图4: PCA后成分的热力图
plt.figure(figsize=(106))
sns.heatmap(pd.DataFrame(pca.components_, columns=feature_names, index=['PC1''PC2']), annot=True, cmap='coolwarm')
plt.title('PCA Component Heatmap')
plt.show()

代码段展示了如何使用PCA对Iris数据集进行降维,生成了多个复杂的图形来进行数据分析:

1. PCA后的散点图:展示了前两个主成分的散点图,并用不同颜色区分不同类别。

2. 原始特征的散点矩阵:展示了原始特征的散点矩阵,并用核密度估计(kde)显示对角线上的分布。

3. PCA后的解释方差比率图:展示了每个主成分的解释方差比率,以及累积解释方差。

4. PCA后成分的热力图:展示了前两个主成分与原始特征之间的关系。

2. 线性判别分析 (LDA, Linear Discriminant Analysis)

线性判别分析(LDA)是一种监督式降维方法,通过最大化类间距离和最小化类内距离来找到最佳投影方向,使得不同类别的样本在新的低维空间中更加可分离。

核心原理

LDA的核心思想是最大化类间散布矩阵  和类内散布矩阵  的比值,从而找到最佳投影方向。

公式

1. 计算类内散布矩阵

其中, 是类别数,是第类,是第个样本,是第 类的均值向量。

2. 计算类间散布矩阵

其中, 是第  类的样本数量, 是总体均值向量。

3. 求解特征值问题

通过最大化 Fisher 判别准则:

这可以转化为特征值问题:

其中,  是特征值,  是对应的特征向量。

4. 选取投影矩阵

选择前  个最大的特征值对应的特征向量构成投影矩阵 

5. 数据投影

将原始数据投影到新的低维空间:

公式推导

步骤 1:计算类内散布矩阵

类内散布矩阵  表示同一类别内样本之间的离散程度。计算公式为:

其中, 表示第类,是属于第类的第个样本,是第 类的均值向量。

步骤 2:计算类间散布矩阵

类间散布矩阵  表示不同类别之间均值的离散程度。计算公式为:

其中,  是第  类的均值向量,  是总体均值向量,  是第  类的样本数量。

步骤 3:求解特征值问题

LDA的目标是找到一个投影矩阵 ,使得类间散布和类内散布的比值最大:

这个问题可以转化为求解  的特征值和特征向量:

其中,  是特征值,  是对应的特征向量。

步骤 4:选取投影矩阵

选择前  个最大的特征值对应的特征向量构成投影矩阵 

步骤 5:数据投影

将原始数据投影到新的低维空间:

在这种新的低维空间中,不同类别的样本将更加可分离。

案例

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
import matplotlib.pyplot as plt
import seaborn as sns

# 加载Iris数据集
iris = load_iris()
X = iris.data
y = iris.target
target_names = iris.target_names

# 创建LDA模型
lda = LDA(n_components=2)
X_r2 = lda.fit(X, y).transform(X)

# 创建一个DataFrame,用于可视化
df = pd.DataFrame(X_r2, columns=['LD1''LD2'])
df['target'] = y
df['target_name'] = df['target'].apply(lambda x: target_names[x])

# 绘制LDA结果的散点图
plt.figure(figsize=(108))
sns.scatterplot(x='LD1', y='LD2', hue='target_name', data=df, palette='Set1')
plt.title('LDA of Iris dataset')
plt.xlabel('LD1')
plt.ylabel('LD2')
plt.legend()
plt.grid(True)
plt.show()

# 计算每个类别的LDA投影的均值
means = df.groupby('target_name').mean()

# 绘制每个类别的LDA投影的均值的图形
plt.figure(figsize=(108))
sns.scatterplot(x=means['LD1'], y=means['LD2'], hue=means.index, palette='Set1', s=100, marker='D', edgecolor='black')
for i, txt in enumerate(means.index):
    plt.annotate(txt, (means['LD1'][i], means['LD2'][i]), fontsize=12, weight='bold')
plt.title('Class Means in LDA Space')
plt.xlabel('LD1')
plt.ylabel('LD2')
plt.legend()
plt.grid(True)
plt.show()

# 绘制LDA各线性判别向量的权重图
plt.figure(figsize=(126))
components_df = pd.DataFrame(lda.coef_, columns=iris.feature_names, index=target_names)
components_df.plot(kind='bar', ax=plt.gca())
plt.title('LDA Coefficients')
plt.xlabel('Features')
plt.ylabel('Coefficient value')
plt.legend(loc='best')
plt.grid(True)
plt.show()

3. 奇异值分解 (SVD, Singular Value Decomposition)

奇异值分解(SVD)是一种矩阵分解技术,它将一个矩阵分解为三个矩阵的乘积。SVD常用于数据降维、噪声去除和推荐系统中。

核心原理

SVD将数据矩阵分解为左奇异矩阵、奇异值矩阵和右奇异矩阵的乘积,从而实现数据的降维。

公式

设有数据矩阵 ,奇异值分解公式为:

其中:

  •  是左奇异矩阵,其列为左奇异向量。
  •  是对角矩阵,其对角线元素为奇异值。
  •  是右奇异矩阵,其列为右奇异向量。

通过选取前  个最大的奇异值及其对应的奇异向量,可以实现数据的降维。

公式推导

步骤 1:计算协方差矩阵

对于数据矩阵 ,计算其协方差矩阵 

步骤 2:求解特征值问题

对协方差矩阵  进行特征值分解:

其中,  是特征值,  是对应的特征向量。

步骤 3:计算奇异值和奇异向量

奇异值  为协方差矩阵  的特征值  的平方根:

左奇异向量  通过如下公式计算:

步骤 4:构建奇异值分解

将特征向量 作为右奇异矩阵的列,左奇异向量作为左奇异矩阵的列,奇异值构成对角矩阵,得到奇异值分解:

步骤 5:数据降维

选取前  个最大的奇异值及其对应的奇异向量,构成降维后的矩阵:

其中, 的前列,的前个对角元素,的前 列。

案例

使用一个合成的高维数据集,通过SVD将其降维到2维,并展示降维前后的数据分布和重要特征。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import TruncatedSVD

# 生成一个合成高维数据集
np.random.seed(42)
n_samples = 1000
n_features = 50
X = np.random.rand(n_samples, n_features)

# 在高维数据中添加一些结构
for i in range(n_samples):
    if i % 2 == 0:
        X[i, :10] += 5
    else:
        X[i, 10:20] += 5

# 进行奇异值分解
svd = TruncatedSVD(n_components=2)
X_reduced = svd.fit_transform(X)

# 可视化原始数据的特征分布(随机选择两组特征进行对比)
plt.figure(figsize=(126))

plt.subplot(121)
plt.scatter(X[:, 0], X[:, 1], alpha=0.7, c='blue', edgecolors='k', s=50)
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.title('Feature Distribution in Original High-dimensional Space')

plt.subplot(122)
plt.scatter(X[:, 10], X[:, 11], alpha=0.7, c='red', edgecolors='k', s=50)
plt.xlabel('Feature 11')
plt.ylabel('Feature 12')
plt.title('Feature Distribution in Original High-dimensional Space')

plt.tight_layout()
plt.show()

# 可视化降维后的数据分布
plt.figure(figsize=(86))
plt.scatter(X_reduced[:, 0], X_reduced[:, 1], alpha=0.7, c='green', edgecolors='k', s=50)
plt.xlabel('Component 1')
plt.ylabel('Component 2')
plt.title('Data Distribution after SVD Dimensionality Reduction')
plt.show()

# 计算并可视化每个奇异值对应的方差解释比例
explained_variance = svd.explained_variance_ratio_
cumulative_explained_variance = np.cumsum(explained_variance)

plt.figure(figsize=(86))
plt.bar(range(len(explained_variance)), explained_variance, alpha=0.7, align='center',
        label='Individual explained variance')
plt.step(range(len(cumulative_explained_variance)), cumulative_explained_variance, where='mid',
         label='Cumulative explained variance')
plt.ylabel('Explained variance ratio')
plt.xlabel('Principal components')
plt.legend(loc='best')
plt.title('Explained Variance by Different Principal Components')
plt.show()

4. 独立成分分析 (ICA, Independent Component Analysis)

独立成分分析(ICA)是一种用于信号处理的降维技术,旨在将混合信号分离为相互独立的源信号。

核心原理

ICA假设观测信号是若干独立源信号的线性组合,通过最大化非高斯性或最小化互信息,分离出源信号。

公式

设有观测信号矩阵 ,其中  是样本数量, 是信号数量。ICA的目标是找到一个分离矩阵 ,使得:

其中, 是源信号矩阵, 是分离矩阵。

公式推导

步骤 1:中心化和白化

首先将数据中心化和白化处理,即将数据变换为零均值且各维度间不相关。

中心化处理:

白化处理:

其中,  是协方差矩阵的特征值对角矩阵,  是协方差矩阵的特征向量矩阵。

步骤 2:最大化非高斯性

利用信息论中的非高斯性度量(如负熵)来最大化信号的非高斯性,从而分离出独立成分。

负熵的近似公式为:

其中, 是一个非高斯性函数,  是投影后的信号,  是高斯信号。

步骤 3:迭代优化

通过迭代优化算法(如快速ICA算法),求解分离矩阵 ,使得源信号  最大化非高斯性。

快速ICA算法的迭代步骤如下:

  1. 随机初始化分离矩阵 
  2. 在每次迭代中更新 

其中, 是非高斯性函数(如 ),  是其导数。3. 对  进行正交化处理。4. 重复步骤2和3,直到 收敛。

步骤 4:数据投影

最终得到分离矩阵  后,将数据投影到独立成分空间:

案例

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import sawtooth
from sklearn.decomposition import FastICA
from sklearn.datasets import make_blobs

# 生成样本数据
np.random.seed(0)
n_samples = 2000
time = np.linspace(08, n_samples)

# 生成独立信号
s1 = np.sin(2 * time)  # 正弦波
s2 = np.sign(np.sin(3 * time))  # 方波
s3 = sawtooth(2 * np.pi * time)  # 锯齿波,使用sawtooth函数

S = np.c_[s1, s2, s3]
S += 0.2 * np.random.normal(size=S.shape)  # 添加噪声

# 混合数据
A = np.array([[111], [0.521.0], [1.51.02.0]])  # 混合矩阵
X = np.dot(S, A.T)  # 观测信号

# ICA 分解
ica = FastICA(n_components=3)
S_ = ica.fit_transform(X)  # 重构信号
A_ = ica.mixing_  # 重构混合矩阵

# 结果可视化
plt.figure(figsize=(128))

# 原始信号
plt.subplot(311)
plt.title("Original Signals")
for i, sig in enumerate(S.T):
    plt.plot(sig, label=f"Signal {i+1}")
plt.legend()

# 混合信号
plt.subplot(312)
plt.title("Mixed Signals")
for i, sig in enumerate(X.T):
    plt.plot(sig, label=f"Mixed Signal {i+1}")
plt.legend()

# 分离信号
plt.subplot(313)
plt.title("Separated Signals (after ICA)")
for i, sig in enumerate(S_.T):
    plt.plot(sig, label=f"Separated Signal {i+1}")
plt.legend()

plt.tight_layout()
plt.show()

# 对比原始信号和分离信号的相关系数矩阵
def plot_correlation_matrix(S, S_):
    correlation = np.corrcoef(S.T, S_.T)[:33:]
    plt.figure(figsize=(66))
    plt.imshow(correlation, cmap='viridis', aspect='auto')
    plt.colorbar()
    plt.title("Correlation Matrix between Original and Separated Signals")
    plt.xlabel("Separated Signals")
    plt.ylabel("Original Signals")
    plt.xticks(range(3), ["Separated 1""Separated 2""Separated 3"])
    plt.yticks(range(3), ["Original 1""Original 2""Original 3"])
    plt.show()

plot_correlation_matrix(S, S_)

5. 非负矩阵分解 (NMF, Non-negative Matrix Factorization)

非负矩阵分解(NMF)是一种矩阵分解方法,将一个非负矩阵分解为两个非负矩阵的乘积。NMF常用于图像处理、文本挖掘和推荐系统中。

核心原理

NMF假设数据矩阵由若干非负基矩阵的线性组合构成,通过最小化重构误差,将数据矩阵分解为两个非负矩阵。

公式

设有非负数据矩阵 ,NMF的目标是找到两个非负矩阵  和 ,使得:

其中,  是基的数量,通常远小于  和 

NMF的优化目标是最小化重构误差,如 Frobenius 范数:

公式推导

步骤 1:初始化

随机初始化  和  为非负矩阵。

步骤 2:迭代更新

通过迭代优化算法(如乘法更新规则),更新  和 ,使得重构误差最小。

乘法更新规则如下:

其中, 表示矩阵  的第  行第  列元素。

步骤 3:收敛判断

重复迭代更新步骤,直到重构误差收敛或达到预设的迭代次数。

步骤 4:数据重构

最终得到  和  后,将数据矩阵重构为:

其中,  表示基矩阵,  表示系数矩阵。

案例

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import NMF
from sklearn.datasets import load_iris
from sklearn.preprocessing import MinMaxScaler

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

# 数据标准化
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)

# 应用NMF进行降维
nmf = NMF(n_components=2, random_state=42)
X_nmf = nmf.fit_transform(X_scaled)

plt.figure(figsize=(146))

# 可视化原始数据的分布
plt.subplot(121)
sns.scatterplot(x=X[:, 0], y=X[:, 1], hue=y, palette="viridis")
plt.title("Distribution of Original Data")
plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[1])

# 可视化NMF降维后的数据
plt.subplot(122)
sns.scatterplot(x=X_nmf[:, 0], y=X_nmf[:, 1], hue=y, palette="viridis")
plt.title("Distribution of Data after NMF Dimensionality Reduction")
plt.xlabel("NMF Component 1")
plt.ylabel("NMF Component 2")
plt.show()

# 查看NMF组件
components = nmf.components_

# 可视化NMF组件
plt.figure(figsize=(104))
for i, comp in enumerate(components):
    plt.subplot(12, i+1)
    plt.bar(iris.feature_names, comp)
    plt.title(f"NMF Component {i+1}")
plt.tight_layout()
plt.show()

# 查看每个样本在NMF组件上的权重
plt.figure(figsize=(106))
sns.heatmap(X_nmf, cmap="viridis", cbar=True, xticklabels=[f"NMF Component {i+1}" for i in range(2)])
plt.title("Weights of Each Sample on NMF Components")
plt.xlabel("NMF Component")
plt.ylabel("Sample")
plt.show()

6. 核PCA (KPCA, Kernel PCA)

核PCA(Kernel PCA)是一种非线性降维方法,通过将数据映射到高维特征空间,然后在该特征空间中进行PCA,实现对非线性数据的降维。它利用核函数技巧,无需显式计算高维映射。

核心原理

核PCA的核心思想是利用核函数将数据隐式地映射到高维特征空间,在该特征空间中进行PCA,通过选择合适的核函数,可以处理复杂的非线性数据结构。

公式

设有数据矩阵 ,核PCA的步骤如下:

1. 计算核矩阵

其中, 是核函数,如高斯核 

2. 中心化核矩阵

其中, 是全为1的  矩阵。

3. 特征值分解

其中, 是特征值, 是对应的特征向量。

4. 选取主成分

按照特征值的大小从大到小排序,选择前  个最大的特征值对应的特征向量。

5. 数据投影

将原始数据投影到新的低维空间:

其中, 是前  个特征向量构成的矩阵。

公式推导

步骤 1:计算核矩阵

利用核函数 ,计算数据矩阵  的核矩阵 

常用的核函数包括线性核、径向基函数(RBF)核和多项式核。

步骤 2:中心化核矩阵

为了在特征空间中进行PCA,需要对核矩阵进行中心化处理。中心化后的核矩阵  计算如下:

其中, 是全为1的  矩阵, 和  分别表示每行和每列的均值。

步骤 3:特征值分解

对中心化后的核矩阵  进行特征值分解:

其中, 是特征值, 是对应的特征向量。

步骤 4:选取主成分

按特征值的大小从大到小排序,选择前  个最大的特征值对应的特征向量,构成投影矩阵 

步骤 5:数据投影

将原始数据投影到新的低维空间:

在这种新的低维空间中,数据的主要非线性结构得以保留。

案例

使用一个标准的数据集,进行KPCA降维~

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_circles
from sklearn.decomposition import PCA, KernelPCA
from sklearn.preprocessing import StandardScaler
from mpl_toolkits.mplot3d import Axes3D

# 生成数据
X, y = make_circles(n_samples=400, factor=0.3, noise=0.05, random_state=0)

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

# 应用KPCA降维到二维
kpca = KernelPCA(n_components=2, kernel='rbf', gamma=15)
X_kpca_2d = kpca.fit_transform(X_scaled)

# 应用KPCA降维到三维
kpca_3d = KernelPCA(n_components=3, kernel='rbf', gamma=15)
X_kpca_3d = kpca_3d.fit_transform(X_scaled)

# 绘制原始数据的二维散点图
plt.figure(figsize=(125))
plt.subplot(121)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='viridis')
plt.title('Original Data')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')

# 绘制KPCA降维后的二维散点图
plt.subplot(122)
plt.scatter(X_kpca_2d[:, 0], X_kpca_2d[:, 1], c=y, cmap='viridis')
plt.title('KPCA Reduced Data (2D)')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')

plt.show()

# 绘制KPCA降维后的三维散点图
fig = plt.figure(figsize=(86))
ax = fig.add_subplot(111, projection='3d')
scatter = ax.scatter(X_kpca_3d[:, 0], X_kpca_3d[:, 1], X_kpca_3d[:, 2], c=y, cmap='viridis')
legend1 = ax.legend(*scatter.legend_elements(), title="Classes")
ax.add_artist(legend1)
ax.set_title('KPCA Reduced Data (3D)')
ax.set_xlabel('Principal Component 1')
ax.set_ylabel('Principal Component 2')
ax.set_zlabel('Principal Component 3')

plt.show()

7. 多维尺度分析 (MDS, Multidimensional Scaling)

多维尺度分析(MDS)是一种非线性降维方法,通过保留数据点之间的距离关系,将高维数据映射到低维空间。MDS常用于可视化和探索数据结构。

核心原理

MDS的核心思想是通过优化一个目标函数,使得低维空间中的数据点之间的距离尽可能接近原始高维空间中的距离。

公式

设有距离矩阵 ,其中  表示数据点  和  之间的距离。MDS的步骤如下:

1. 构建距离矩阵

2. 计算中心化距离矩阵

其中, 是单位矩阵, 是全为1的  矩阵。

3. 特征值分解

其中, 是对角矩阵,其对角线元素为特征值, 是特征向量矩阵。

4. 选取主成分

选择前  个最大的特征值对应的特征向量,构成新的低维空间坐标。

5. 数据投影

将原始数据点投影到新的低维空间:

其中, 是前  个特征向量, 是前  个特征值对应的对角矩阵。

公式推导

步骤 1:构建距离矩阵

对于数据矩阵 ,计算每对数据点之间的欧氏距离,构成距离矩阵 

步骤 2:计算中心化距离矩阵

构建中心化矩阵 

利用中心化矩阵  计算中心化距离矩阵 

步骤 3:特征值分解

对中心化距离矩阵  进行特征值分解:

其中, 是对角矩阵,其对角线元素为特征值, 是特征向量矩阵。

步骤 4:选取主成分

选择前  个最大的特征值对应的特征向量,构成新的低维空间坐标。

步骤 5:数据投影

将原始数据点投影到新的低维空间:

在这种新的低维空间中,数据点之间的距离关系尽可能接近原始高维空间中的距离。

案例

均值散布嵌入(MDS)可以将高维数据映射到低维空间中,同时尽量保持数据点之间的距离关系。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.manifold import MDS
from sklearn.preprocessing import StandardScaler

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

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

# 使用MDS进行降维,将数据从4维降至2维
mds = MDS(n_components=2, random_state=42)
X_mds = mds.fit_transform(X_scaled)

# 绘制降维后的数据
plt.figure(figsize=(106))

# 绘制不同类别的散点图
for i in range(len(np.unique(y))):
    plt.scatter(X_mds[y == i, 0], X_mds[y == i, 1], label=f'Class {i}', alpha=0.7)

plt.title('MDS Visualization of Iris Dataset')
plt.xlabel('Component 1')
plt.ylabel('Component 2')
plt.legend()
plt.grid(True)
plt.show()


8. t-分布邻域嵌入 (t-SNE, t-Distributed Stochastic Neighbor Embedding)

t-SNE是一种非线性降维方法,主要用于数据可视化。它通过将高维数据映射到低维空间,保留数据点之间的局部结构,从而实现对数据的低维表示。

核心原理

t-SNE的核心思想是将高维空间中的点对距离转换为概率分布,在低维空间中构建一个相似的概率分布,通过最小化两者之间的Kullback-Leibler散度来实现降维。

公式

设有数据矩阵 ,t-SNE的步骤如下:

1. 计算高维空间中的相似度

对于高维数据点  和 ,计算其相似度 

其中, 是根据数据点  的分布调整的参数。

2. 计算低维空间中的相似度:

对于低维数据点  和 ,计算其相似度 

3. 最小化Kullback-Leibler散度

通过梯度下降法,最小化高维和低维空间中相似度分布之间的Kullback-Leibler散度:

4. 数据投影

将原始数据点  投影到低维空间 

公式推导

步骤 1:计算高维空间中的相似度

对每对高维数据点  和 ,计算其高维空间中的相似度 

其中, 是根据数据点  的分布调整的参数,使得  满足归一化条件。

步骤 2:计算低维空间中的相似度

对每对低维数据点  和 ,计算其低维空间中的相似度 

步骤 3:最小化Kullback-Leibler散度

通过最小化高维和低维空间中相似度分布之间的Kullback-Leibler散度,实现数据的降维:

利用梯度下降法,更新低维数据点  的位置,以最小化KL散度。

步骤 4:数据投影

经过迭代优化后,得到低维空间中的数据点 ,实现对原始数据的降维表示。

案例

在高维数据中寻找结构和聚类~

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.manifold import TSNE

# 加载手写数字数据集
digits = load_digits()
X = digits.data
y = digits.target

# 使用t-SNE进行降维,降到2维
tsne = TSNE(n_components=2, random_state=42)
X_tsne = tsne.fit_transform(X)

# 绘制原始数据的散点图
plt.figure(figsize=(128))
plt.subplot(121)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.get_cmap("jet"10))
plt.title('Original Data')
plt.colorbar()

# 绘制t-SNE降维后的散点图
plt.subplot(122)
plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap=plt.cm.get_cmap("jet"10))
plt.title('t-SNE Visualization')
plt.colorbar()

plt.tight_layout()
plt.show()
  • 左侧子图展示了原始数据的散点图,每个点的颜色对应于其所属的数字类别。
  • 右侧子图展示了使用t-SNE降维后的散点图,同样使用了颜色编码来表示数字类别。

理解了,接下来我将详细介绍局部线性嵌入(Locally Linear Embedding, LLE)和独立成分分析(Uniform Manifold Approximation and Projection, UMAP)的相关信息。

9. 局部线性嵌入 (Locally Linear Embedding, LLE)

介绍

局部线性嵌入(LLE)是一种非线性降维方法,通过保持局部数据点之间的线性关系来实现数据的降维。

核心原理

LLE的核心思想是假设高维数据的每个数据点可以由其局部邻域的线性组合表示,通过优化重构系数,得到数据在低维空间的表示。

公式

设有数据矩阵 ,LLE的步骤如下:

1. 找出邻域:对于每个数据点 ,找出其最近的  个邻居。

2. 重构权重:对于每个数据点 ,通过最小化重构误差来计算其在低维空间的表示:

其中, 是重构系数,满足 

3. 构建权重矩阵:构建权重矩阵 ,其中  表示数据点  和其邻居  之间的重构权重。

4. 低维表示:通过特征值分解或者其他方法得到数据在低维空间的表示。

公式推导

步骤 1:找出邻域

对于每个数据点 ,找出其最近的  个邻居,这可以通过距离度量如欧氏距离来实现。

步骤 2:重构权重

对于每个数据点 ,通过最小化重构误差来计算其在低维空间的表示。重构误差最小化的优化问题可以表示为:

其中, 是重构系数,满足 

步骤 3:构建权重矩阵

根据计算得到的重构系数 ,构建权重矩阵 ,其中  表示数据点  和其邻居  之间的重构权重。

步骤 4:低维表示

通过对权重矩阵  进行特征值分解或其他方法,得到数据在低维空间的表示。

案例

局部线性嵌入(LLE)尝试保持数据点之间的局部线性关系,以便在低维空间中嵌入数据。

import matplotlib.pyplot as plt
from sklearn.datasets import make_swiss_roll
from sklearn.manifold import LocallyLinearEmbedding

# 生成一个瑞士卷状数据集
X, _ = make_swiss_roll(n_samples=3000, noise=0.2, random_state=42)

# 使用LLE进行降维,目标是将3维数据降到2维
lle = LocallyLinearEmbedding(n_neighbors=10, n_components=2, random_state=42)
X_lle = lle.fit_transform(X)

# 绘制原始数据和降维后的数据
fig = plt.figure(figsize=(126))

# 原始数据的散点图
ax1 = fig.add_subplot(121, projection='3d')
ax1.scatter(X[:, 0], X[:, 1], X[:, 2], c=X[:, 2], cmap=plt.cm.Spectral)
ax1.set_title('Original 3D Swiss Roll')

# LLE降维后的散点图
ax2 = fig.add_subplot(122)
ax2.scatter(X_lle[:, 0], X_lle[:, 1], c=X[:, 2], cmap=plt.cm.Spectral)
ax2.set_title('LLE Projection')

plt.tight_layout()
plt.show()
  • 左图(原始数据):展示了原始的三维瑞士卷数据集。颜色编码代表了数据点在第三个维度上的取值。
  • 右图(降维后的数据):展示了经过 LLE 算法降维后的二维数据。同样使用了颜色编码,使得每个数据点在三维空间中的高度通过颜色体现在了二维平面上。

10. UMAP

UMAP 是一种先进的非线性降维算法,主要用于高维数据的可视化和聚类。它能够有效地保留数据的局部和全局结构,并能够捕捉数据中的非线性关系。

介绍

UMAP是一种基于流形学习理论的非线性降维方法,由McInnes和Healy于2018年提出。它可以将高维数据映射到低维空间,同时保持数据的局部结构和全局结构的特征。UMAP常用于高维数据的可视化、聚类分析和特征学习,特别是在探索复杂数据结构和模式识别方面表现优异。

核心原理

UMAP的核心原理包括以下几个关键步骤:

  • 构建邻域图:根据高维数据点之间的距离(通常使用欧氏距离或其他度量),构建一个邻域图。在UMAP中,采用的是基于最近邻的方法来确定每个数据点的邻居。

  • 优化距离:通过优化一个结合多样性和平滑性的损失函数,调整数据点在低维空间中的表示,以保持高维空间中的局部结构和全局结构。

  • 距离计算:在低维空间中,通过最小化原始数据点之间的距离和在高维空间中的距离之间的差异,调整数据点的位置。

公式推导

UMAP的具体数学推导涉及复杂的优化问题和图论方法,以下是UMAP的主要数学公式和推导思路的概述:

步骤 1:构建邻域图

对于给定的高维数据集 ,首先根据距离度量(如欧氏距离)构建一个邻域图。通常使用的方法是基于  近邻或者基于距离阈值来确定每个数据点的邻居集合。

步骤 2:优化距离

在UMAP中,优化目标是最小化在高维空间中的距离和在低维空间中的距离之间的差异。具体地,UMAP使用以下损失函数来调整数据点在低维空间中的位置:

其中:

  •  是低维空间中的数据点的集合。
  •  是数据点  的邻居集合。
  •  是权重,用于调整邻域数据点之间的距离。
  •  是在高维空间中数据点  和  之间的距离的分布。
  •  是在低维空间中数据点  和  之间的距离的分布。

步骤 3:距离计算

通过梯度下降等优化算法,调整低维空间中数据点的位置 ,以最小化上述损失函数。具体的优化过程涉及到高维空间中距离分布  和低维空间中距离分布  的计算和调整。

案例

当使用非线性降维算法UMAP时,一个经典的案例是在高维数据集上进行降维并可视化。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from umap import UMAP

# 加载手写数字数据集(MNIST)
mnist = fetch_openml('mnist_784', version=1)
X, y = mnist.data / 255.0, mnist.target.astype(int)

# 只选择一部分数据进行演示
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, train_size=0.1, random_state=42)

# 使用UMAP进行降维
umap = UMAP(n_components=2, random_state=42)
X_umap = umap.fit_transform(X_train)

# 绘制降维后的数据点
plt.figure(figsize=(108))
plt.scatter(X_umap[:, 0], X_umap[:, 1], c=y_train, cmap='Spectral', s=5)
plt.colorbar(boundaries=np.arange(11)-0.5).set_ticks(np.arange(10))
plt.title('UMAP Projection of MNIST')
plt.xlabel('UMAP1')
plt.ylabel('UMAP2')
plt.show()

最后

大家有问题可以直接在评论区留言即可~

喜欢本文的朋友可以收藏、点赞、转发起来!
需要本文PDF的同学,扫码备注「模型汇总」即可~ 
关注本号,带来更多算法干货实例,提升工作学习效率!
最后,给大家准备了《机器学习学习小册》PDF版本16大块的内容,124个问题总结

推荐阅读

原创、超强、精华合集
100个超强机器学习算法模型汇总
机器学习全路线
机器学习各个算法的优缺点
7大方面,30个最强数据集
6大部分,20 个机器学习算法全面汇总
铁汁,都到这了,别忘记点赞呀~

深夜努力写Python
Python、机器学习算法
 最新文章