Machine Learning机器学习之高维数据降维(主成分分析PCA、线性判别分析、自编码器超级无敌详细讲解)
高维数据降维是指将具有大量特征的数据转换为具有更少特征的数据的过程。在现实世界中,许多数据集具有大量的特征,这可能会增加建模的复杂性,并导致维度灾难(Curse of Dimensionality)问题的出现。高维数据降维的目的是减少特征的数量,同时保留数据中最重要的信息,以便更好地理解数据、可视化数据、加快计算速度和提高模型性能。主成分分析PCA,局部线性嵌入LLE算法应用与实现、自编码器算法
目录
博主介绍:✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神,答疑解惑、坚持优质作品共享。本人是掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战,深受全网粉丝喜爱与支持✌有需要可以联系作者我哦!
🍅文末三连哦🍅
👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟
前言
高维数据降维是指将具有大量特征的数据转换为具有更少特征的数据的过程。在现实世界中,许多数据集具有大量的特征,这可能会增加建模的复杂性,并导致维度灾难(Curse of Dimensionality)问题的出现。高维数据降维的目的是减少特征的数量,同时保留数据中最重要的信息,以便更好地理解数据、可视化数据、加快计算速度和提高模型性能。
思想原理:
维度灾难:随着特征数量的增加,数据空间的维度也会增加。高维数据具有稀疏性和冗余性,这可能会导致模型过拟合、计算复杂度增加和样本稀疏性等问题,即维度灾难。
信息压缩:高维数据降维的目标是在保留数据中最重要信息的前提下,减少数据的维度。通过降维,可以将数据中的冗余信息和噪声过滤掉,从而使得数据更加紧凑和易于处理。
特征选择和特征提取:高维数据降维可以通过特征选择(Feature Selection)和特征提取(Feature Extraction)两种方式实现。特征选择是从原始特征中选择最重要的一部分特征,而特征提取则是通过某种变换将原始特征转换为新的特征空间,以减少特征的数量。
降维方法:常见的高维数据降维方法包括主成分分析(PCA)、线性判别分析(LDA)、t-分布邻近嵌入(t-SNE)、自编码器(Autoencoder)等。这些方法在保留数据信息的同时,可以有效地减少数据的维度。
一、常见数据降维方法简介
1、降维方法分类情况
特征选择:
- 特征选择是从原始特征集中选择最重要的特征子集,保留最相关的特征,而丢弃不相关的或冗余的特征。这些方法不改变原始特征的形式,只是选择性地保留或删除特征。
- 常见的特征选择方法包括:
- 过滤法(Filter Methods):根据特征的统计量(如方差、相关系数等)或其他评价标准对特征进行评估和排序,然后选择排名靠前的特征子集。
- 包装法(Wrapper Methods):通过建立预测模型来评估特征子集的性能,根据模型性能选择最佳特征子集。常见的包装法包括递归特征消除(Recursive Feature Elimination)和正向逐步选择(Forward Stepwise Selection)等。
- 嵌入法(Embedded Methods):在模型训练过程中,通过正则化项或其他方式对特征进行选择,例如 L1 正则化(Lasso)和决策树剪枝等。
特征提取:
- 特征提取是通过某种变换将原始特征转换为新的特征空间,以减少特征的数量,同时保留数据的主要信息。这些方法可以将原始特征进行线性或非线性变换,从而得到新的特征表示。
- 常见的特征提取方法包括:
- 主成分分析(Principal Component Analysis,PCA):通过线性变换将原始特征投影到新的特征空间,使得投影后的特征具有最大的方差。PCA 是一种常用的线性降维方法。
- 线性判别分析(Linear Discriminant Analysis,LDA):在保持类别信息的同时最大化类间距离和最小化类内距离,从而得到新的特征空间。LDA 通常用于分类任务。
- t-分布邻近嵌入(t-distributed Stochastic Neighbor Embedding,t-SNE):通过非线性变换将高维数据映射到低维空间,使得相似的样本在低维空间中距离更近。t-SNE 通常用于可视化高维数据。
- 自编码器(Autoencoder):通过神经网络模型将原始特征压缩到低维空间,然后再将低维表示重构为原始特征,以此来学习数据的有效表示。自编码器在无监督学习中广泛应用于特征学习和数据降维。
二、常见数据降维分析之主成分分析
2.1背景介绍
主成分分析(Principal Component Analysis,PCA)是一种常用的线性降维技术,用于将高维数据转换为低维数据,同时保留尽可能多的原始数据信息。PCA 旨在找到数据中最重要的特征,并将其映射到新的特征空间上,以便更好地理解数据结构、可视化数据、减少计算成本和提高模型性能。接下来,我们将深入介绍 PCA 的思想原理、数学公式、实现步骤以及应用场景。
2.2思想原理
PCA 的核心思想是通过线性变换将原始数据投影到新的特征空间,使得投影后的特征具有最大的方差。这意味着,通过 PCA 转换后的特征保留了原始数据中包含的大部分信息,同时尽可能减少了特征之间的相关性。具体来说,PCA 的实现步骤如下:
1. 中心化数据:首先,对原始数据进行中心化处理,即将每个特征的均值减去其平均值,以确保数据的均值为零。
2. 计算协方差矩阵:接下来,计算中心化后的数据的协方差矩阵。协方差矩阵反映了不同特征之间的相关性程度,其对角线上的元素表示每个特征的方差,非对角线上的元素表示不同特征之间的协方差。
3. 求取特征值和特征向量:对协方差矩阵进行特征值分解,得到特征值和对应的特征向量。特征值表示了数据在特征空间上的方差,而特征向量表示了数据在特征空间上的方向。
4. 选择主成分:按照特征值的大小对特征向量进行排序,选择前 k 个特征向量作为主成分(Principal Components),其中 k 是希望降维后的维度。
5. 投影到新空间:将原始数据投影到由选定的主成分构成的新的特征空间上,得到降维后的数据。
2.3数学公式
1. 数据中心化:
若原始数据矩阵为,其中每行表示一个样本,每列表示一个特征,则中心化后的数据矩阵 可以表示为:
其中,是每个特征的均值向量。
2. 协方差矩阵:
对中心化后的数据矩阵计算协方差矩阵:
其中,是样本数量。
3. 特征值分解:
对协方差矩阵进行特征值分解:
其中,是第个特征值,是对应的特征向量。
4. 选择主成分:
根据特征值的大小对特征向量进行排序,选择前 k 个特征向量作为主成分。
5. 投影到新空间:
将原始数据矩阵投影到由选定的主成分构成的新的特征空间上,得到降维后的数据矩阵:
其中,是包含前 k 个特征向量的矩阵。
2.4PCA算法实现(Python完整代码)
首先我们基于NumPy 来生成两个类别共100个样本点。第一步,我们将使用 NumPy 库生成随机的样本点,然后使用 Matplotlib 库进行可视化。每个样本点都有三个特征,代表三维空间中的坐标。我们将随机生成两个类别的样本点,并将它们可视化出来。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 设置随机种子,以便结果可重现
np.random.seed(0)
# 随机生成两个类别的样本点
num_samples = 50
class_1 = np.random.randn(num_samples, 3) # 第一个类别的样本点
class_2 = np.random.randn(num_samples, 3) # 第二个类别的样本点
# 绘制三维散点图
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 绘制第一个类别的样本点
ax.scatter(class_1[:, 0], class_1[:, 1], class_1[:, 2], c='r', label='Class 1')
# 绘制第二个类别的样本点
ax.scatter(class_2[:, 0], class_2[:, 1], class_2[:, 2], c='b', label='Class 2')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('Randomly Generated 3D Samples')
ax.legend()
plt.show()
图1 随机样本点生成结果
第二步,我们将通过定义pca函数实现对三维数据降维处理。然后,我们可以使用 Matplotlib 将降维后的二维数据可视化出来,同时绘制特征向量。
定义pca函数对数据降维处理:
def pca(X, k):
"""
主成分分析(PCA)实现。
参数:
- X(numpy.ndarray):形状为(n_samples,n_features)的输入数据矩阵。
- k(int):要保留的主成分数量。
返回值:
- numpy.ndarray:形状为(n_samples,k)的转换后的数据矩阵。
- numpy.ndarray:形状为(n_features,k)的前 k 个特征向量。
"""
# 中心化数据
X_centered = X - np.mean(X, axis=0)
# 计算数据的协方差矩阵
cov_matrix = np.cov(X_centered, rowvar=False)
# 对协方差矩阵进行特征值分解
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# 选择前 k 个特征向量
top_k_eigenvectors = eigenvectors[:, :k]
# 将数据投影到新的特征空间上
transformed_data = np.dot(X_centered, top_k_eigenvectors)
return transformed_data, top_k_eigenvectors
可视化数据结果其中,其中红色点代表第一个类别,蓝色点代表第二个类别。特征向量用箭头表示,箭头的方向和长度表示了数据变换后的主要方向和重要程度。
# 绘制二维分布图
plt.figure(figsize=(8, 6))
plt.scatter(transformed_data[:num_samples, 0], transformed_data[:num_samples, 1], c='r', label='Class 1')
plt.scatter(transformed_data[num_samples:, 0], transformed_data[num_samples:, 1], c='b', label='Class 2')
# 绘制特征向量
origin = np.zeros(2) # 原点
plt.quiver(*origin, top_k_eigenvectors[0, 0], top_k_eigenvectors[1, 0], color='r', scale=3)
plt.quiver(*origin, top_k_eigenvectors[0, 1], top_k_eigenvectors[1, 1], color='b', scale=3)
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.title('PCA Result: 2D Distribution')
plt.legend()
plt.grid(True)
plt.show()
图2 二维空间分布特征向量可视化结果
完整源代码(Python):
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子,以便结果可重现
np.random.seed(0)
# 随机生成两个类别的样本点
num_samples = 50
class_1 = np.random.randn(num_samples, 3) # 第一个类别的样本点
class_2 = np.random.randn(num_samples, 3) # 第二个类别的样本点
# 绘制三维散点图
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 绘制第一个类别的样本点
ax.scatter(class_1[:, 0], class_1[:, 1], class_1[:, 2], c='r', label='Class 1')
# 绘制第二个类别的样本点
ax.scatter(class_2[:, 0], class_2[:, 1], class_2[:, 2], c='b', label='Class 2')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('Randomly Generated 3D Samples')
ax.legend()
plt.show()
def pca(X, k):
"""
主成分分析(PCA)实现。
参数:
- X(numpy.ndarray):形状为(n_samples,n_features)的输入数据矩阵。
- k(int):要保留的主成分数量。
返回值:
- numpy.ndarray:形状为(n_samples,k)的转换后的数据矩阵。
- numpy.ndarray:形状为(n_features,k)的前 k 个特征向量。
"""
# 中心化数据
X_centered = X - np.mean(X, axis=0)
# 计算数据的协方差矩阵
cov_matrix = np.cov(X_centered, rowvar=False)
# 对协方差矩阵进行特征值分解
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# 选择前 k 个特征向量
top_k_eigenvectors = eigenvectors[:, :k]
# 将数据投影到新的特征空间上
transformed_data = np.dot(X_centered, top_k_eigenvectors)
return transformed_data, top_k_eigenvectors
# 将样本点合并为一个数据集
X = np.vstack([class_1, class_2])
# 应用PCA算法进行降维
transformed_data, top_k_eigenvectors = pca(X, 2)
# 绘制二维分布图
plt.figure(figsize=(8, 6))
plt.scatter(transformed_data[:num_samples, 0], transformed_data[:num_samples, 1], c='r', label='Class 1')
plt.scatter(transformed_data[num_samples:, 0], transformed_data[num_samples:, 1], c='b', label='Class 2')
# 绘制特征向量
origin = np.zeros(2) # 原点
plt.quiver(*origin, top_k_eigenvectors[0, 0], top_k_eigenvectors[1, 0], color='r', scale=3)
plt.quiver(*origin, top_k_eigenvectors[0, 1], top_k_eigenvectors[1, 1], color='b', scale=3)
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.title('PCA Result: 2D Distribution')
plt.legend()
plt.grid(True)
plt.show()
2.5应用场景
PCA 广发应用机器学习领域的数据处理:
- 数据可视化:通过降维将高维数据映射到二维或三维空间,以便更好地理解数据结构和关系。
- 数据压缩:降低数据的维度可以节省存储空间和计算成本,提高数据处理效率。
- 特征提取:将原始特征转换为新的特征空间,以提取数据中的关键信息和模式。
- 去除噪声:通过降维可以过滤掉数据中的噪声和冗余信息,使得模型更加稳健和高效。
三、常见数据降维分析之线性判别分析
3.1背景分析
线性判别分析(Linear Discriminant Analysis,LDA)是一种监督学习算法,用于降低数据维度并找到最佳分类特征。与PCA不同,LDA是为了降维后的数据点尽可能容易区分出来,因此在分类问题中更常用。
图3 PCA与LDA一维度投影示例
3.2思想原理
LDA 的主要思想是将数据投影到一个低维空间,以便在新空间中能够最大化类别之间的差异性,同时最小化同一类别内的差异性。具体来说,LDA 将数据投影到一条直线(在一维情况下)、一个平面(在二维情况下)或一个超平面(在高维情况下),以最大化类别之间的距离(即类间散布矩阵)与最小化同一类别内的方差(即类内散布矩阵)之比。
LDA 的降维步骤包括:
- 计算每个类别的均值向量(类均值)。
- 计算类间散布矩阵和类内散布矩阵。
- 根据公式进行特征值求解,计算散布矩阵的特征值和特征向量。
- 选择前 k 个特征值对应的特征向量(k 为降维后的维度)构成投影矩阵。
- 通过将数据投影到选定的特征向量构成的子空间中。
3.4LDA算法实现
根据3.2的LDA算法思想,我们按照上述步骤实现LDA降维函数定义。代码如下图,步骤不再累述:
# 定义LDA函数
def lda(X, y, n_components):
"""
返回结果
Returns:
numpy.ndarray: Transformed data matrix with shape (n_samples, n_components).
"""
# Step 1: 计算每个类别的均值向量(类均值)
class_means = []
for c in np.unique(y):
class_means.append(np.mean(X[y == c], axis=0))
# Step 2: 计算类内散布矩阵和类间散布矩阵
Sw = np.zeros((X.shape[1], X.shape[1])) # 类内散布矩阵
Sb = np.zeros((X.shape[1], X.shape[1])) # 类间散布矩阵
overall_mean = np.mean(X, axis=0)
for c, mean_vec in zip(np.unique(y), class_means):
class_samples = X[y == c]
class_scatter_matrix = np.zeros((X.shape[1], X.shape[1]))
for sample in class_samples:
sample, mean_vec = sample.reshape(-1, 1), mean_vec.reshape(-1, 1)
class_scatter_matrix += (sample - mean_vec).dot((sample - mean_vec).T)
Sw += class_scatter_matrix
Sb += len(class_samples) * (mean_vec - overall_mean).dot((mean_vec - overall_mean).T)
# Step 3: 计算散布矩阵的特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(np.linalg.inv(Sw).dot(Sb))
# Step 4: 选择前 k 个特征值对应的特征向量(k 为降维后的维度)
eig_pairs = [(np.abs(eigenvalues[i]), eigenvectors[:, i]) for i in range(len(eigenvalues))]
eig_pairs = sorted(eig_pairs, key=lambda k: k[0], reverse=True)
w_matrix = np.hstack((eig_pairs[i][1].reshape(X.shape[1], 1) for i in range(n_components)))
# Step 5: 将数据投影到选定的特征向量构成的子空间中
X_lda = X.dot(w_matrix)
return X_lda
算法应用:加载了 Iris 数据集,然后调用了上面实现的 LDA 算法进行降维。最后,使用 Matplotlib 绘制了 LDA 降维结果的散点图。在图中,每个点代表一个样本,不同颜色的点表示不同类别的 Iris 鸢尾花,分别是 Setosa、Versicolor 和 Virginica。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
# 加载 Iris 数据集
iris = load_iris()
X = iris.data
y = iris.target
def lda(X, y, n_components):
# Step 1: 计算每个类别的均值向量(类均值)
class_means = []
for c in np.unique(y):
class_means.append(np.mean(X[y == c], axis=0))
# Step 2: 计算类内散布矩阵和类间散布矩阵
Sw = np.zeros((X.shape[1], X.shape[1])) # 类内散布矩阵
Sb = np.zeros((X.shape[1], X.shape[1])) # 类间散布矩阵
overall_mean = np.mean(X, axis=0)
for c, mean_vec in zip(np.unique(y), class_means):
class_samples = X[y == c]
class_scatter_matrix = np.zeros((X.shape[1], X.shape[1]))
for sample in class_samples:
sample, mean_vec = sample.reshape(-1, 1), mean_vec.reshape(-1, 1)
class_scatter_matrix += (sample - mean_vec).dot((sample - mean_vec).T)
Sw += class_scatter_matrix
Sb += len(class_samples) * (mean_vec - overall_mean).dot((mean_vec - overall_mean).T)
# Step 3: 计算散布矩阵的特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(np.linalg.inv(Sw).dot(Sb))
# Step 4: 选择前 k 个特征值对应的特征向量(k 为降维后的维度)
eig_pairs = [(np.abs(eigenvalues[i]), eigenvectors[:, i]) for i in range(len(eigenvalues))]
eig_pairs = sorted(eig_pairs, key=lambda k: k[0], reverse=True)
w_matrix = np.hstack([eig_pairs[i][1].reshape(X.shape[1], 1) for i in range(n_components)])
# Step 5: 将数据投影到选定的特征向量构成的子空间中
X_lda = X.dot(w_matrix)
return X_lda
# 调用 LDA 算法进行降维
X_lda = lda(X, y, n_components=2)
# 可视化 LDA 降维结果
plt.figure(figsize=(8, 6))
colors = ['r', 'g', 'b']
labels = ['Setosa', 'Versicolor', 'Virginica']
for i in range(3):
plt.scatter(X_lda[y == i, 0], X_lda[y == i, 1], color=colors[i], label=labels[i])
plt.xlabel('LD1')
plt.ylabel('LD2')
plt.title('LDA Dimensionality Reduction of Iris Dataset')
plt.legend()
plt.grid(True)
plt.show()
图4 LDA对三个属性数据降维效果
3.5应用场景
-
模式识别和分类:LDA 可以用于模式识别和分类问题,特别是当类别之间有明显的线性边界时。例如,人脸识别、手写数字识别等图像分类问题。
-
特征提取和降维:LDA 可以用于提取数据中的关键特征,并将数据降低到更低维度的空间中。这对于高维数据的可视化和压缩具有重要意义。例如,在图像处理和计算生物学中,可以使用 LDA 将数据降维到更容易处理和理解的空间中。
-
异常检测:LDA 可以用于检测数据中的异常点或异常模式。通过比较新样本与已知类别的分布,可以识别出与预期模式不同的样本。
-
信号处理:LDA 可以用于信号处理领域,例如语音识别、音频分类等,以区分不同的信号模式或类别。
-
文本分类:在自然语言处理领域,LDA 可以用于文本分类问题,例如垃圾邮件过滤、情感分析等,以区分文本数据中的不同类别或主题。
四、常见数据降维分析之t-分布邻近嵌入
4.1背景介绍
t-分布邻近嵌入(t-distributed Stochastic Neighbor Embedding,t-SNE)是一种非线性降维技术,用于将高维数据映射到低维空间。它是一种流形学习技术,旨在保留数据之间的局部结构,并在降维后尽可能地保持数据点之间的相对距离。
4.2思想原理
t-SNE 的核心思想是利用高维数据点之间的相似度来构建一个概率分布,然后在低维空间中尽可能地保持相似度。具体来说,它通过以下步骤实现降维:
-
计算相似度:对于给定的高维数据集,首先计算每对数据点之间的相似度。通常使用高斯核函数来度量两个数据点之间的相似度,距离越近,相似度越高。
-
构建条件概率分布:根据相似度计算每个数据点之间的条件概率分布。对于每个数据点,计算它与其他数据点的相似度,并将相似度转换为条件概率。
-
优化嵌入:在低维空间中随机初始化数据点的位置,并利用梯度下降等优化方法来最小化高维空间中的相似度和低维空间中的条件概率分布之间的差异。目标是在低维空间中找到一个投影,使得高维数据点之间的相对距离尽可能地得到保留。
4.3t-分布邻近嵌入算法
局部线性嵌入(Locally Linear Embedding,LLE),下面是实现 LLE 算法的关键步骤:
-
选择邻域参数: 对于每个数据点,选择其最近的 k 个邻居作为其邻域。
-
重构权重矩阵: 对于每个数据点,使用其邻域内的数据点来重构它本身。这涉及到求解一个线性系统,以最小化原始数据点与其邻域内数据点的线性组合之间的误差。
-
计算嵌入坐标: 根据重构权重矩阵,将数据点映射到低维空间。这可以通过求解一个最小化误差函数的优化问题来实现。
def select_neighbors(X, k):
# 计算每个数据点的欧氏距离矩阵
dist_matrix = np.sqrt(np.sum((X[:, np.newaxis] - X) ** 2, axis=2))
# 获取每个数据点的 k 个最近邻索引
neighbor_indices = np.argsort(dist_matrix, axis=1)[:, 1:k+1]
return neighbor_indices
def compute_weights(X, neighbor_indices):
n_samples = X.shape[0]
W = np.zeros((n_samples, n_samples))
for i, neighbors in enumerate(neighbor_indices):
# 计算局部权重矩阵
Z = X[neighbors] - X[i]
C = Z @ Z.T
w = linalg.spsolve(C, np.ones(k)) # 使用稀疏求解器求解线性系统
W[i, neighbors] = w / np.sum(w) # 归一化权重
return W
# 定义LLM算法函数
def lle(X, k, n_components):
n_samples = X.shape[0]
# Step 1: 选择邻域参数
neighbor_indices = select_neighbors(X, k)
# Step 2: 重构权重矩阵
W = compute_weights(X, neighbor_indices)
# Step 3: 计算嵌入坐标
M = np.eye(n_samples) - W
eigvals, eigvecs = linalg.eigs(M, k=n_components+1, which='SM')
idx = np.argsort(np.abs(eigvals))
return eigvecs[:, idx[1:n_components+1]]
接下来我们通过随机生成1000个数据点来检验LLM算法实现的降维效果。
import numpy as np
from scipy.sparse import linalg
import matplotlib.pyplot as plt
def select_neighbors(X, k):
# 计算每个数据点的欧氏距离矩阵
dist_matrix = np.sqrt(np.sum((X[:, np.newaxis] - X) ** 2, axis=2))
# 获取每个数据点的 k 个最近邻索引
neighbor_indices = np.argsort(dist_matrix, axis=1)[:, 1:k+1]
return neighbor_indices
def compute_weights(X, neighbor_indices):
n_samples = X.shape[0]
W = np.zeros((n_samples, n_samples))
for i, neighbors in enumerate(neighbor_indices):
# 计算局部权重矩阵
Z = X[neighbors] - X[i]
C = Z @ Z.T
w = linalg.spsolve(C, np.ones(k)) # 使用稀疏求解器求解线性系统
W[i, neighbors] = w / np.sum(w) # 归一化权重
return W
def lle(X, k, n_components):
n_samples = X.shape[0]
# Step 1: 选择邻域参数
neighbor_indices = select_neighbors(X, k)
# Step 2: 重构权重矩阵
W = compute_weights(X, neighbor_indices)
# Step 3: 计算嵌入坐标
M = np.eye(n_samples) - W
eigvals, eigvecs = linalg.eigs(M, k=n_components+1, which='SM')
idx = np.argsort(np.abs(eigvals))
return eigvecs[:, idx[1:n_components+1]]
# 随机生成1000个数据点,包含3个属性特征
X = np.random.randn(1000, 3) # 生成三维随机数据
k = 3 # 邻域参数
n_components = 2 # 降维后的维度
embedding = lle(X, k, n_components)
# 绘制降维后的数据点
plt.figure(figsize=(8, 6))
plt.scatter(embedding[:, 0], embedding[:, 1])
plt.xlabel('Component 1')
plt.ylabel('Component 2')
plt.title('LLE Visualization')
plt.grid(True)
plt.show()
图5 LLM算法实现降维效果
五、自编码器(Autoencoder)
5.1自编码器思想与原理
自编码器(Autoencoder)是一种无监督学习模型,它通过尝试重构输入数据来学习有效的数据表示。自编码器通常由两部分组成:编码器(Encoder)和解码器(Decoder)。编码器将输入数据映射到潜在空间中的低维表示,而解码器则将该低维表示映射回原始数据空间。
自编码器的目标是最小化输入数据与重构数据之间的差异,这可以通过最小化重构误差来实现。通常使用均方误差(MSE)或者交叉熵作为重构误差的度量。
自编码器的训练过程通常分为以下步骤:
- 将输入数据传递给编码器,获取潜在表示。
- 使用潜在表示重构原始数据,并计算重构误差。
- 使用反向传播算法优化网络参数,以最小化重构误差。
自编码器通常被用于数据压缩、特征学习和去噪等应用中。它们也可以用作生成模型的一部分,例如生成对抗网络(GAN)中的生成器部分。
常见的自编码器类型包括标准自编码器、稀疏自编码器、去噪自编码器、变分自编码器等。、
5.2自编码器算法
基于PyTorch 构建一个简单的全连接自编码器,并在 MNIST 数据集上进行训练和测试。自编码器的编码器部分由一个全连接层组成,激活函数为 ReLU;解码器部分也是一个全连接层,激活函数为 Sigmoid。在训练过程中,使用二元交叉熵作为损失函数,并使用 Adam 优化器进行优化。最后,通过编码和解码图像,可视化原始图像与重构图像。(注意运行环境需要安装pytorch;代码动态下载MNIST数据集在data文件夹中,可能需要点时间等待;迭代次数选择20,如果环境装有GPU可以根据实际情况调整;因为时间关系实际效果还有很大提升空间(训练效果一般,仅供参考学习,勿喷哦!)各位伙伴可以分享自己的训练参数情况,或者更好的重构图像代码)
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
# 定义自编码器模型
class Autoencoder(nn.Module):
def __init__(self, input_dim, latent_dim):
super(Autoencoder, self).__init__()
self.encoder = nn.Sequential(
nn.Linear(input_dim, latent_dim),
nn.ReLU()
)
self.decoder = nn.Sequential(
nn.Linear(latent_dim, input_dim),
nn.Sigmoid()
)
def forward(self, x):
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return decoded
# 加载MNIST数据集并预处理
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
train_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=256, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=256, shuffle=False)
# 实例化自编码器模型
input_dim = 28 * 28 # 输入大小为28x28=784
latent_dim = 64 # 潜在空间维度
autoencoder = Autoencoder(input_dim, latent_dim)
# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = torch.optim.Adam(autoencoder.parameters(), lr=0.001)
# 训练自编码器
num_epochs = 20
for epoch in range(num_epochs):
for data in train_loader:
img, _ = data
img = img.view(img.size(0), -1)
output = autoencoder(img)
loss = criterion(output, img)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 使用自编码器进行编码和解码
encoded_imgs = autoencoder.encoder(test_dataset.data.float().view(-1, input_dim))
decoded_imgs = autoencoder.decoder(encoded_imgs)
# 可视化原始图像与重构图像
n = 10 # 可视化样本数
plt.figure(figsize=(20, 4))
for i in range(n):
# 原始图像
ax = plt.subplot(2, n, i + 1)
plt.imshow(test_dataset.data[i].numpy(), cmap='gray')
plt.title("Original")
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# 重构图像
ax = plt.subplot(2, n, i + 1 + n)
plt.imshow(decoded_imgs[i].detach().numpy().reshape(28, 28), cmap='gray')
plt.title("Reconstructed")
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
5.3 运行结果:
图6 原始图像与重构图像代码
六、总结
今天我们涉及了机器学习的各个方面,包括传统机器学习算法(如线性回归、逻辑回归、决策树、随机森林、支持向量机等)、降维算法(如主成分分析、局部线性嵌入、t-分布邻近嵌入等)、深度学习算法(如自编码器)、以及一些常用的数据集和数据处理技巧。我们还介绍了这些算法的原理、应用场景和代码实现。总的来说,今天的内容涵盖了机器学习的基础知识和常见技术,为进一步学习和应用机器学习提供了基础。
最后,创作不易!非常感谢大家的关注、点赞、收藏、评论啦!谢谢四连哦!好人好运连连,学习进步!工作顺利哦!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)