深入探究Python机器学习算法:无监督学习(聚类算法如 K-Means、DBSCAN,降维算法如 PCA、SVD)

devtools/2025/3/5 1:07:44/

文章目录

  • 深入探究 Python 机器学习算法:无监督学习
    • 聚类算法
      • K - Means聚类
        • 算法流程
        • K值选择方法
        • 聚类结果的稳定性分析和评估方法
      • 层次聚类
        • 算法原理和实现过程
        • 连接方法特点和适用场景
        • 可视化方法
      • DBSCAN密度聚类
        • 算法原理
        • 优势和局限性
    • 降维算法
      • 主成分分析(PCA)
        • 数学原理
        • 应用实例
        • 实现步骤
        • 局限性和改进方法
      • 奇异值分解(SVD)
        • 原理
        • 与PCA的关系和区别
        • Python实现
      • 其他降维算法
        • 局部线性嵌入(LLE)
        • 等距映射(Isomap)

深入探究 Python 机器学习算法:无监督学习

在数据的浩瀚海洋中,无监督学习宛如一座指引方向的灯塔,助力我们从海量未标记数据里挖掘出潜藏的信息与模式。今天,让我们深入探索无监督学习中的聚类与降维算法,并借助Python代码真切感受它们的强大功能。

聚类算法

聚类算法旨在将数据集中的样本划分成不同的组或簇,让同一簇内的样本相似度颇高,而不同簇间的样本差异显著。

K - Means聚类

算法流程
  1. 初始聚类中心选择
    • 随机选择:从数据集中随机挑选K个样本点当作初始聚类中心,实现简单,但初始选择的随机性易使最终聚类结果陷入局部最优。
    • K - Means++算法:依据特定概率选择初始聚类中心,优先挑选那些与已有聚类中心相距较远的点,使初始中心分布更合理,降低陷入局部最优的可能性。
  2. 样本分配:运用距离度量(如欧几里得距离),算出每个样本与K个聚类中心的距离,将样本归入距离最近的聚类中心所在的簇。
  3. 聚类中心更新:计算每个簇内所有样本的均值,以此作为新的聚类中心。随后不断重复样本分配与聚类中心更新步骤,直至聚类中心不再变动或达到预设的迭代次数。

以下是用Python实现K - Means聚类的详尽代码示例,涵盖数据生成、完整聚类流程及结果可视化:

python">import os
os.environ["OMP_NUM_THREADS"] = "1"
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)# 初始化KMeans模型,设置聚类数为3
kmeans = KMeans(n_clusters = 3)
# 对数据进行聚类
kmeans.fit(data)
# 获取每个样本的聚类标签
labels = kmeans.labels_
# 获取聚类中心
centers = kmeans.cluster_centers_# 可视化聚类结果
plt.scatter(data[:, 0], data[:, 1], c = labels)
plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='X')
plt.title('K - Means Clustering Results')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()

在这里插入图片描述

K值选择方法
  1. 手肘法:计算不同K值下的聚类误差平方和(SSE),并绘制K与SSE的关系曲线。曲线中斜率突变的点即“手肘点”,对应的K值通常为较优选择。
python">import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)sse = []
for k in range(1, 11):kmeans = KMeans(n_clusters = k)kmeans.fit(data)sse.append(kmeans.inertia_)# 绘制手肘图
plt.plot(range(1, 11), sse)
plt.title('Elbow Method')
plt.xlabel('Number of Clusters (k)')
plt.ylabel('Sum of Squared Errors (SSE)')
plt.show()

在这里插入图片描述

  1. 轮廓系数法:计算每个样本的轮廓系数,轮廓系数越大,聚类效果越好。遍历不同的K值,选取轮廓系数最大时的K值。
python">import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)silhouette_scores = []
for k in range(2, 11):kmeans = KMeans(n_clusters = k)kmeans.fit(data)score = silhouette_score(data, kmeans.labels_)silhouette_scores.append(score)# 绘制轮廓系数图
plt.plot(range(2, 11), silhouette_scores)
plt.title('Silhouette Coefficient Method')
plt.xlabel('Number of Clusters (k)')
plt.ylabel('Silhouette Coefficient')
plt.show()

在这里插入图片描述

  1. Gap统计量法:对比数据的真实分布与不同K值下聚类结果的分布,选择使Gap统计量最大的K值。
python">import numpy as np
from sklearn.cluster import KMeans
from sklearn.utils import resample
import matplotlib.pyplot as plt# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)def compute_gap_statistic(data, k, B = 10):# 计算数据在k个簇下的聚类误差kmeans = KMeans(n_clusters = k)kmeans.fit(data)wk = kmeans.inertia_# 生成B个参考数据集并计算其聚类误差wkb = []for _ in range(B):ref_data = resample(data, replace = True, n_samples = len(data))kmeans_ref = KMeans(n_clusters = k)kmeans_ref.fit(ref_data)wkb.append(kmeans_ref.inertia_)log_wk = np.log(wk)log_wkb_mean = np.mean(np.log(wkb))gap = log_wkb_mean - log_wkreturn gapgap_values = []
k_values = range(1, 11)
for k in k_values:gap = compute_gap_statistic(data, k)gap_values.append(gap)# 可视化 Gap 统计量
plt.plot(k_values, gap_values, marker='o')
plt.title('Gap Statistic for Different Values of k')
plt.xlabel('Number of Clusters (k)')
plt.xticks(k_values)  # 设置 x 轴刻度为 k 的值
plt.ylabel('Gap Statistic')
plt.grid(True)
plt.show()# 这里可根据gap_values选择合适的k值,通常选择gap值最大时的k

在这里插入图片描述

聚类结果的稳定性分析和评估方法

稳定性可通过多次运行K - Means算法,观察聚类结果的一致性来判断。评估方法除上述轮廓系数法等K值选择方法外,还能采用均方误差等指标,均方误差越小,聚类效果越佳。以下是计算均方误差的代码示例:

python">import numpy as np
from sklearn.cluster import KMeans# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)kmeans = KMeans(n_clusters = 3)
kmeans.fit(data)
labels = kmeans.labels_
centers = kmeans.cluster_centers_sse = 0
for i in range(len(data)):cluster_center = centers[labels[i]]sse += np.linalg.norm(data[i] - cluster_center) ** 2
print(f'Sum of Squared Errors: {sse}')

层次聚类

算法原理和实现过程
  1. 凝聚式:从每个样本各自为一类开始,持续合并相似的类,直至所有样本归为一类或满足停止条件。
  2. 分裂式:从所有样本同属一类开始,逐步将类分裂成更小的类,直到每个样本成为单独的类或满足停止条件。
连接方法特点和适用场景
  1. 单链接:以两个簇中距离最近的样本点的距离作为簇间距离,能找出细长形状的簇,适用于数据分布较为分散且形状不规则的情形。
  2. 全链接:以两个簇中距离最远的样本点的距离作为簇间距离,倾向于形成紧凑的簇,对含噪声和离群点的数据较为鲁棒。
  3. 平均链接:以两个簇中所有样本点对的平均距离作为簇间距离,综合了单链接和全链接的特性,在多数情况下表现较为稳定。
可视化方法

树状图以树形结构展示层次聚类的结果,横坐标为样本点,纵坐标为距离或相似度。通过树状图能直观看到各个簇的合并或分裂过程以及簇间的相似性。在Python中,可使用scipy库绘制树状图:

python">import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)Z = linkage(data, 'ward')
plt.figure(figsize=(10, 5))
dendrogram(Z)
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('Sample Index')
plt.ylabel('Distance')
plt.show()

在这里插入图片描述

  1. 尝试不同的连接方法
    可以尝试不同的连接方法(如 ‘single’、‘complete’、‘average’)并对比它们的树状图,这样能更直观地看到不同连接方法对聚类结果的影响。
    在这里插入图片描述

DBSCAN密度聚类

算法原理
  1. 核心点、边界点、噪声点的定义和识别方法:在半径ε内包含至少MinPts个点的点为核心点;在核心点的邻域内,但本身不是核心点的点为边界点;既不是核心点也不是边界点的点为噪声点。
  2. 邻域半径(ε)和最小点数(MinPts)的选择方法和影响:通常依据经验或对数据的初步分析来选择。ε过大可能致使不同簇合并,过小则可能将一个簇分割成多个小簇;MinPts过大可能使很多点被误判为噪声点,过小则可能无法准确识别簇的边界。
优势和局限性

优势在于能找出任意形状的簇,对含噪声的数据鲁棒性强;局限性是难以很好地反映高维数据及密度变化大的数据的密度差异,计算复杂度较高。

python">import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)# 调整 eps 和 min_samples 参数
dbscan = DBSCAN(eps=0.15, min_samples=5)
dbscan.fit(data)
labels = dbscan.labels_# 检查是否存在噪声点
has_noise = -1 in labels
if has_noise:print("数据集中存在噪声点。")
else:print("数据集中不存在噪声点。")# 可视化聚类结果,区分核心点、边界点和噪声点
core_samples_mask = np.zeros_like(labels, dtype=bool)
core_samples_mask[dbscan.core_sample_indices_] = Trueunique_labels = set(labels)
colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):if k == -1:# 黑色表示噪声点col = [0, 0, 0, 1]class_member_mask = (labels == k)xy = data[class_member_mask & core_samples_mask]plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),markeredgecolor='k', markersize=14)xy = data[class_member_mask & ~core_samples_mask]plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),markeredgecolor='k', markersize=6)plt.title('DBSCAN Clustering Results')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()

在这里插入图片描述

降维算法

降维算法用于将高维数据转换为低维数据,在保留数据主要特征的同时降低数据维度,削减计算复杂度并方便数据可视化。

主成分分析(PCA)

数学原理

通过计算数据的协方差矩阵,求解其特征值和特征向量,将特征值从大到小排序,对应的特征向量即为各个主成分的方向,选取前k个特征值对应的特征向量作为主成分,实现数据降维。

应用实例
  1. 图像压缩:对图像数据进行PCA,保留主要的主成分,去除次要成分,实现图像压缩。以下是对简单图像数据进行PCA压缩的示例(假设图像数据为二维矩阵形式):
python">import numpy as np
from sklearn.decomposition import PCA
from PIL import Image
import matplotlib.pyplot as plt# 读取图像并转换为numpy数组
image = Image.open('example_image.jpg').convert('L')
image_array = np.array(image)# 按行展平图像数据
flattened_image = image_array.reshape(image_array.shape[0], -1)# 进行PCA,设置保留90%的方差
pca = PCA(n_components=0.9)
pca.fit(flattened_image)
compressed_image = pca.transform(flattened_image)# 重构图像
reconstructed_image = pca.inverse_transform(compressed_image)
reconstructed_image = reconstructed_image.reshape(image_array.shape)# 可视化原始图像和重构图像
plt.subplot(1, 2, 1)
plt.imshow(image_array, cmap='gray')
plt.title('Original Image')
plt.subplot(1, 2, 2)
plt.imshow(reconstructed_image, cmap='gray')
plt.title('Reconstructed Image')
plt.show()

在这里插入图片描述

  1. 高维数据可视化:将高维数据投影到低维空间,如二维或三维空间,便于直观观察数据的分布和特征。
实现步骤
  1. 首先对数据进行标准化,确保各个特征具有相同的尺度。
  2. 计算协方差矩阵。
  3. 进行特征值分解。
  4. 根据特征值的大小选择主成分。
python">import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler# 生成一些随机高维数据
np.random.seed(0)
data = np.random.rand(100, 5)# 数据标准化
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data)# 初始化PCA,设置降维后的维度为2
pca = PCA(n_components = 2)
pca.fit(scaled_data)
reduced_data = pca.transform(scaled_data)# 查看主成分解释的方差比例
print(pca.explained_variance_ratio_)
局限性和改进方法

局限性包括对数据的线性假设较强,可能无法妥善处理非线性数据等。核主成分分析(KPCA)通过引入核函数将数据映射到高维特征空间,再进行主成分分析,可处理非线性数据。以下是KPCA的简单实现示例:

python">import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import KernelPCA
from sklearn.preprocessing import StandardScaler# 生成一些随机数据
np.random.seed(0)
data = np.random.rand(100, 2)# 数据标准化
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data)# 初始化KernelPCA,使用rbf核函数
kpca = KernelPCA(n_components=1, kernel='rbf')
reduced_data = kpca.fit_transform(scaled_data)# 可视化原始数据
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(data[:, 0], data[:, 1], c='b', label='Original Data')
plt.title('Original Data')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()# 可视化降维后的数据
# 为了在二维平面上展示一维降维结果,我们将降维后的数据放在 x 轴,y 轴设为 0
plt.subplot(1, 2, 2)
plt.scatter(reduced_data, np.zeros_like(reduced_data), c='r', label='Reduced Data')
plt.title('Reduced Data after Kernel PCA')
plt.xlabel('Reduced Feature')
plt.legend()plt.tight_layout()
plt.show()

在这里插入图片描述

奇异值分解(SVD)

原理

对于任意一个矩阵A,可分解为A = UΣVᵀ,其中U是左奇异向量矩阵,Σ是奇异值矩阵,V是右奇异向量矩阵。奇异值是矩阵A的特征值的平方根,左奇异向量和右奇异向量分别是AAT和ATA的特征向量。

与PCA的关系和区别

SVD可用于计算PCA中的协方差矩阵的特征值和特征向量,但SVD更通用,可处理非方阵。在数据降维中,两者都可用于提取数据的主要特征,但SVD在处理大规模数据和推荐系统等方面应用更为广泛。

Python实现

使用Python的numpy库可便捷实现SVD算法,通过调用相关函数进行矩阵分解和低秩近似操作。

python">import numpy as np# 生成一个随机矩阵
A = np.random.rand(5, 3)# 进行SVD分解
U, s, Vh = np.linalg.svd(A)# 构建奇异值矩阵
Sigma = np.zeros((A.shape[0], A.shape[1]))
Sigma[:A.shape[1], :A.shape[1]] = np.diag(s)# 低秩近似,例如保留前2个奇异值
k = 2
U_k = U[:, :k]
Sigma_k = Sigma[:k, :k]
Vh_k = Vh[:k, :]
A_approx = U_k.dot(Sigma_k).dot(Vh_k)print('Original Matrix A:\n', A)
print('Approximated Matrix A_approx:\n', A_approx)# 计算 Frobenius 范数误差
error = np.linalg.norm(A - A_approx, 'fro')
print('Frobenius norm error:', error)# 计算原矩阵的 Frobenius 范数
norm_A = np.linalg.norm(A, 'fro')
# 计算相对误差
relative_error = error / norm_A
print('Relative error:', relative_error)

相对误差较小:如果相对误差较小(例如小于 0.1),说明近似矩阵与原矩阵非常接近,低秩近似的效果较好,保留了原矩阵的大部分信息。
相对误差较大:如果相对误差较大(例如大于 0.5),则表明近似矩阵与原矩阵的差异比较明显,可能在近似过程中丢失了较多重要信息。
结合矩阵特性分析
矩阵的奇异值分布:如果原矩阵的奇异值衰减很快,即前几个奇异值远大于后面的奇异值,那么保留前几个奇异值进行低秩近似通常能得到较好的效果,误差会相对较小。反之,如果奇异值衰减缓慢,那么仅保留少数奇异值进行近似时,误差可能会比较大。
矩阵的用途:在不同的应用场景中,对近似误差的容忍度不同。例如,在图像压缩中,如果只是用于大致的预览,可能可以接受相对较大的误差;但在一些对精度要求较高的科学计算或数据处理任务中,可能需要更小的误差。

其他降维算法

局部线性嵌入(LLE)

原理:
局部线性嵌入假设数据在局部是线性的,即每个数据点可以由其邻域内的其他点的线性组合来近似表示。LLE 首先计算每个数据点的局部重构权重,然后固定这些权重,寻找一个低维嵌入,使得在低维空间中数据点仍然可以由相同的权重进行线性重构。通过最小化重构误差来得到低维表示。
应用场景:适合处理具有流形结构的数据,如手写数字识别、人脸识别等领域,能有效捕捉数据的局部几何结构。

python">from sklearn.datasets import make_swiss_roll
from sklearn.manifold import LocallyLinearEmbedding
import matplotlib.pyplot as plt# 生成瑞士卷数据集
X, color = make_swiss_roll(n_samples=1000, random_state=42)# 初始化 LLE 模型
lle = LocallyLinearEmbedding(n_components=2, n_neighbors=10)
X_lle = lle.fit_transform(X)# 可视化降维结果
plt.scatter(X_lle[:, 0], X_lle[:, 1], c=color)
plt.title('Locally Linear Embedding')
plt.show()

在这里插入图片描述

等距映射(Isomap)

原理:
等距映射是一种基于流形学习的降维方法,它试图在低维空间中保持数据点之间的测地距离(即流形上的最短路径距离)。首先构建数据点的邻域图,计算图中任意两点之间的最短路径距离(如使用 Dijkstra 算法或 Floyd - Warshall 算法),然后使用多维缩放(MDS)方法将这些距离映射到低维空间。
应用场景:常用于处理具有复杂非线性结构的数据,如高维生物数据、图像数据等。

python">from sklearn.datasets import make_swiss_roll
from sklearn.manifold import Isomap
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3# 生成瑞士卷数据集
X, color = make_swiss_roll(n_samples=1000, random_state=42)# 初始化 Isomap 模型
isomap = Isomap(n_components=2, n_neighbors=10)
X_isomap = isomap.fit_transform(X)# 创建一个包含两个子图的图形窗口
fig = plt.figure(figsize=(12, 6))# 可视化原始数据(三维)
ax1 = fig.add_subplot(121, projection='3d')
ax1.scatter(X[:, 0], X[:, 1], X[:, 2], c=color)
ax1.set_title('Original Swiss Roll Data (3D)')
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
ax1.set_zlabel('Z')# 可视化降维后的数据(二维)
ax2 = fig.add_subplot(122)
ax2.scatter(X_isomap[:, 0], X_isomap[:, 1], c=color)
ax2.set_title('Reduced Data after Isomap (2D)')
ax2.set_xlabel('Feature 1')
ax2.set_ylabel('Feature 2')plt.tight_layout()
plt.show()

在这里插入图片描述


http://www.ppmy.cn/devtools/164609.html

相关文章

鸿蒙5.0实战案例:基于Asset下的高安全级别数据存储

往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录) ✏️ 鸿蒙(HarmonyOS)北向开发知识点记录~ ✏️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~ ✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景&#…

STM32单片机芯片与内部111 STM32 DSP内核 介绍 功能 库与源码

目录 一、STM32F4 的 DSP 功能介绍 二、Cortex-M4 内核的 DSP 和专业 DSP 的区别 三、相关功能 1、BasicMathFunctions 2、FastMathFunctions 3、ComplexMathFunctions 4、FilteringFunctions 5、MatrixFunctions 6、TransformFunctions 7、ControllerFunctions 8、…

Python 如何实现烟花效果的完整代码

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons:JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram,自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 ? 5 IDEA必装的插件&…

mybatis相关的面试题及答案第一弹

1. MyBatis的核心组件有哪些?它们的作用是什么? 答案: MyBatis的核心组件包括: SqlSessionFactory:负责创建SqlSession对象,是MyBatis的核心工厂。SqlSession:用于执行SQL语句、获取映射器&am…

L-Lipschitz Gershgorin ResNet 网络

大家读完觉得有帮助记得关注和点赞!!! 抽象 深度残差网络 (ResNets) 在计算机视觉任务中取得了巨大的成功,这归因于它们能够保持通过深度架构的梯度流。同时,控制神经网络中的 Lipschitz 绑定已…

[密码学实战]Java生成SM2根证书及用户证书

前言 在国密算法体系中,SM2是基于椭圆曲线密码(ECC)的非对称加密算法,广泛应用于数字证书、签名验签等场景。本文将结合代码实现,详细讲解如何通过Java生成SM2根证书及用户证书,并深入分析其核心原理。 一、证书验证 1.代码运行结果 2.根证书验证 3.用户证书验证 二、…

算法系列之动态规划

动态规划(Dynamic Programming,简称DP)是一种用于解决复杂问题的算法设计技术。它通过将问题分解为更小的子问题,并存储这些子问题的解来避免重复计算,从而提高算法的效率。本文将介绍动态规划的基本概念、适用场景、复…

计算机网络 (第一章)

第一章 计算机网络 概述 1. 定义: 计算机网络主要是由一些通用的、可编程的硬件互连而成的,而这些硬件并非专门用来实现某一特定目的(例如,传送数据或视频信号).这些可编程的硬件能够用来传送多种不同类型的数据,并能支持广泛的和日益增长的…