当前位置: 首页 > news >正文

K-means算法在无监督学习中的应用

K-means算法在无监督学习中的应用

K-means算法是一种典型的无监督学习算法,广泛用于聚类分析。在无监督学习中,模型并不依赖于标签数据,而是根据输入数据的特征进行分组。K-means的目标是将数据集分成K个簇,使得同一簇内的数据点相似度较高,而不同簇之间的数据点相似度较低。它通过寻找数据中的潜在结构来自动划分数据。

K-means算法广泛应用于聚类分析图像分割异常检测等领域。本文将详细介绍K-means算法的原理、数学模型、实现步骤,并从这三个应用方向举例讲解K-means在无监督学习中的应用。


1. K-means算法的原理和数学模型

1.1 K-means算法的基本思想

K-means算法是一种基于划分的聚类方法,目标是将数据集分成K个簇,并通过最小化簇内误差平方和(SSE, Sum of Squared Errors)来实现数据的聚类。K-means算法的核心在于通过不断地更新簇的中心(质心)和重新分配数据点,直到算法收敛。

1.2数学模型

假设我们有一个包含n个数据点的数据集,数据点的特征是d维的。K-means算法的目标是将数据集划分为K个簇,最小化每个簇内的误差平方和。具体的数学模型如下:

  1. 初始化: 随机选择K个数据点作为初始簇的中心(质心),记为 C 1 , C 2 , … , C K C_1, C_2, \dots, C_K C1,C2,,CK

  2. 分配步骤: 将每个数据点 x i x_i xi 分配到距离它最近的簇中心。距离度量通常使用欧氏距离:
    d ( x i , C k ) = ∥ x i − C k ∥ 2 d(x_i, C_k) = \| x_i - C_k \|^2 d(xi,Ck)=xiCk2
    数据点 x i x_i xi 被分配到最近的簇中心 C k C_k Ck

  3. 更新步骤: 更新每个簇的质心,新的质心是该簇所有数据点的均值:
    C k = 1 ∣ S k ∣ ∑ x i ∈ S k x i C_k = \frac{1}{|S_k|} \sum_{x_i \in S_k} x_i Ck=Sk1xiSkxi
    其中, S k S_k Sk 是簇 k k k 中的所有数据点, ∣ S k ∣ |S_k| Sk 是簇的大小。

  4. 停止条件: 重复分配和更新步骤,直到簇中心不再发生变化或达到最大迭代次数。

K-means的目标是最小化簇内误差平方和(SSE),公式如下:
S S E = ∑ k = 1 K ∑ x i ∈ S k ∥ x i − C k ∥ 2 SSE = \sum_{k=1}^K \sum_{x_i \in S_k} \| x_i - C_k \|^2 SSE=k=1KxiSkxiCk2
K-means通过迭代更新簇中心来减少SSE,从而实现最优的簇划分。


2. K-means的实现步骤

K-means算法的实现过程可以分为以下几个主要步骤:

  1. 数据预处理
    • 在应用K-means之前,通常需要对数据进行预处理,包括标准化和降维,尤其是当数据特征维度较高时。
  2. 选择K值
    • K值表示簇的数量。在实际应用中,K的选择非常重要,常用的方法有肘部法则(Elbow Method)来确定最佳K值。
  3. 初始化簇中心
    • 选择K个数据点作为初始簇中心,常用的初始化方法有随机选择K-means++
  4. 迭代更新
    • 分配每个数据点到最近的簇中心。
    • 更新簇中心为簇内所有数据点的均值。
    • 重复步骤直到簇中心不再变化。
  5. 评估聚类效果
    • 可以使用SSE、轮廓系数等指标来评估聚类效果。

3. KMeans类的参数解释

from sklearn.cluster import KMeans# n_clusters: 簇的数量,即 K 值
# init: 初始化中心点的方法,默认为 'k-means++',一种启发式方法来选择初始簇中心以加速收敛
# n_init: 运行 k-means 算法的次数,选择具有最小 SSE 的结果,默认为 'auto' 根据数据集大小自动选择
# max_iter: 单次运行的最大迭代次数,达到最大迭代次数或收敛时停止迭代
# tol: 收敛阈值,两次迭代误差小于此值即认为算法已收敛
# verbose: 是否输出详细信息,默认为 0,不输出
# random_state: 随机数生成器的种子,用于初始化中心点,保持结果可重复
# copy_x: 是否复制输入数据,默认为 True,表示复制输入数据
# algorithm: 计算的算法,'auto', 'full', 'elkan','auto'根据数据自动选择算法,'full'使用传统的 EM 算法,'elkan'是一种更有效的 K-means 算法kmeans = KMeans(n_clusters=8,init='k-means++',n_init='auto',max_iter=300,tol=0.0001,verbose=0,random_state=None,copy_x=True,algorithm='lloyd'
)kmeans.fit(X)

4. 确定最优K值

4.1 数据预处理(前摇)

from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
from sklearn.decomposition import PCAimport matplotlib.pyplot as plt
import seaborn as snssns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})  # 设置主题和字体# 加载数据集
iris = load_iris()
X = iris.data# 使用PCA降维到二维,以便可视化
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)

4.2 肘部法(Elbow Method)

通过绘制不同K值下的SSE(误差平方和),并寻找SSE快速下降的“肘部”位置。

# 计算不同K值下的SSE
sse = []
for k in range(1, 11):kmeans = KMeans(n_clusters=k)kmeans.fit(X_pca)  # 这里X_pca是经过PCA降维后的数据sse.append(kmeans.inertia_)# 绘制SSE曲线
plt.figure(figsize=(8, 6))  # 设置图表大小
plt.plot(range(1, 11), sse, marker='o', color='b', linestyle='-', markersize=8)# 设置中文标题和标签
plt.title('肘部法则选择最佳K值', fontsize=14)
plt.xlabel('簇的数量 (K)', fontsize=12)
plt.ylabel('SSE', fontsize=12)# 显示图表
plt.show()

download

4.3 轮廓系数(Silhouette Score)

衡量聚类质量的指标,轮廓系数越大,表示聚类效果越好。

# 计算不同K值下的轮廓系数
silhouette_scores = []
for k in range(2, 11):  # 由于轮廓系数要求至少有两个簇kmeans = KMeans(n_clusters=k)cluster_labels = kmeans.fit_predict(X_pca)silhouette_avg = silhouette_score(X_pca, cluster_labels)silhouette_scores.append(silhouette_avg)# 绘制轮廓系数曲线
plt.figure(figsize=(8, 6))  # 设置图表大小
plt.plot(range(2, 11), silhouette_scores, marker='o', color='b', linestyle='-', markersize=8)# 设置中文标题和标签
plt.title('轮廓系数选择最佳K值', fontsize=14)
plt.xlabel('簇的数量 (K)', fontsize=12)
plt.ylabel('轮廓系数', fontsize=12)# 显示图表
plt.show()

download

4.4 遍历K值(肉眼比较法)

通过遍历不同K值,并比较它们的可视化效果。
(当使用 肘部法轮廓系数 无法确定K值时候,可遍历K值根据可视化结果比较作为参考)

# 设置图表的整体大小
fig, axes = plt.subplots(2, 4, figsize=(18, 8), sharex=True, sharey=True)  # 2行5列的子图排布# 遍历聚类数量1到8
for k in range(1, 9):kmeans = KMeans(n_clusters=k)kmeans.fit(X_pca)  # 用降维后的数据进行聚类labels = kmeans.labels_  # 聚类标签# 选择子图位置ax = axes[(k - 1) // 4, (k - 1) % 4]# 绘制每个子图ax.scatter(X_pca[:, 0], X_pca[:, 1], c=labels, cmap='viridis', s=50, alpha=0.6)ax.set_title(f'k = {k}', fontsize=12)ax.set_xlabel('特征1', fontsize=10)ax.set_ylabel('特征2', fontsize=10)ax.grid(True)# 调整布局,防止标签重叠
plt.tight_layout()
plt.show()

download


5. K-means算法的应用

K-means算法广泛应用于多个领域,以下文中三个常见的应用方向进行举例:聚类分析图像分割异常检测

5.1 聚类分析

聚类分析旨在将数据集划分为多个簇,使得簇内的数据点相似度高,簇间的数据点相似度低。

5.1.1 数据加载、降维并聚类

from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
from sklearn.decomposition import PCAimport matplotlib.pyplot as plt
import seaborn as snssns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})  # 设置主题和字体# 加载数据集
iris = load_iris()
X = iris.data# 使用PCA降维到二维,以便可视化
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)# 聚类
kmeans = KMeans(n_clusters=3, random_state=42)
clusters = kmeans.fit_predict(X_pca)

5.1.2 绘制聚类散点图

# 可视化聚类结果
plt.figure(figsize=(10, 8))  # 调整画布大小
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})  # 设置主题和字体# 绘制散点图
scatter = sns.scatterplot(x=X_pca[:, 0],y=X_pca[:, 1],hue=clusters,palette='bright',style=clusters,markers=["o", "s", "D"],s=100,  # 调整点的大小edgecolor='black',  # 添加边框颜色linewidth=0.8,  # 边框线宽alpha=0.8,  # 透明度
)# 设置标题和轴标签
plt.title("K-Means聚类结果", fontsize=18, fontweight="bold", pad=10)
plt.xlabel("主成分1", fontsize=14, labelpad=10)
plt.ylabel("主成分2", fontsize=14, labelpad=10)# 设置轴刻度字体大小
plt.tick_params(axis='x', labelsize=12)
plt.tick_params(axis='y', labelsize=12)# 设置图例样式
legend = plt.legend(title="聚类类别",title_fontsize=13,fontsize=12,loc='lower right',  # 调整图例位置bbox_to_anchor=(0.975, 0.025),  # 向左上偏移0.1frameon=True,  # 添加图例边框shadow=True,  # 添加阴影fancybox=True,  # 圆角边框borderpad=1  # 内边距
)
legend.get_frame().set_linewidth(1.2)  # 设置图例边框线宽# 添加网格线样式
plt.grid(color='gray', linestyle='--', linewidth=0.8, alpha=0.3)# 调整布局
plt.tight_layout()# 显示图表
plt.show()

download

5.1.3 添加轮廓线

# 绘制轮廓线
sns.kdeplot(x=X_pca[:, 0],y=X_pca[:, 1],hue=clusters,palette='bright',levels=5,alpha=0.5,linewidths=1.5,ax=scatter,
)

download

5.1.4 添加簇中心点

# 将中心点转换到PCA空间
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1],c='red', marker='X', s=200, label='聚类中心', edgecolor='black', linewidth=2
)  # 绘制中心点

download


5.2 图像分割

图像分割是指将图像划分为多个区域,每个区域的像素在颜色、纹理等特征上具有相似性。K-means算法可以用于图像分割,将图像的每个像素聚类到不同的簇中,从而实现对图像的分割。

5.2.1 导入图片

from sklearn.datasets import load_sample_image
import matplotlib.pyplot as plt# 加载“chinajpg”样本图像
flower = load_sample_image('china.jpg')# 显示图片
plt.figure(figsize=(6, 6))
plt.imshow(flower)
plt.axis('off')  # 禁用轴
plt.show()

download

5.2.2 分割过程

from sklearn.cluster import KMeans
import numpy as np# 加载图像并转换为numpy数组
china = load_sample_image("china.jpg")
china = np.array(china)# 将图像转为二维数组(每个像素为一个数据点)
X = china.reshape(-1, 3)  # 3是RGB通道# K-means聚类,设定聚类数为4
kmeans = KMeans(n_clusters=3, random_state=1)
kmeans.fit(X)# 获取聚类标签
labels = kmeans.labels_# 将标签重新变为图像的形状
segmented_image = labels.reshape(china.shape[0], china.shape[1])

5.2.3 可视化

import seaborn as sns
from mpl_toolkits.mplot3d import Axes3D  # 可视化RGB三维散点图sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})  # 设置主题和字体# 提取RGB通道数据
R = X[:, 0]
G = X[:, 1]
B = X[:, 2]# 创建3D散点图
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')# 使用透明度(alpha)调整点的透明度
scatter = ax.scatter(R, G, B, c=labels, cmap='viridis', s=5, alpha=0.5)  # alpha为透明度# 设置坐标轴标签和标题
ax.set_xlabel('R', fontsize=12, labelpad=10)
ax.set_ylabel('G', fontsize=12, labelpad=10)
ax.set_zlabel('B', fontsize=12, labelpad=10)
ax.set_title('K-means 聚类 RGB 三维散点图', fontsize=14)# 设置更精致的坐标轴刻度
ax.tick_params(axis='both', which='major', labelsize=10)# 显示图形
plt.show()

download

# 可视化图像分割结果
plt.figure(figsize=(8, 6))
plt.imshow(segmented_image, cmap='viridis')
plt.title('图像分割:K-means聚类', fontsize=14)
# plt.axis('off')  # 禁用坐标轴
plt.show()

download

5.2.4 拆分结果

# 将标签重新变为图像的形状
segmented_image_list = []# 创建每个簇的分割图像
for cluster in range(3):  # 假设我们有3个簇# 创建一个全为0的图像(与原图尺寸一致)segmented_image = np.zeros_like(china)# 将属于该簇的像素赋值为原图像素,其他像素设置为黑色# 获取属于该簇的像素的索引cluster_pixels = labels == cluster# 将符合条件的像素赋值segmented_image.reshape(-1, 3)[cluster_pixels] = china.reshape(-1, 3)[cluster_pixels]# 添加到分割图像列表中segmented_image_list.append(segmented_image)# 创建子图布局
fig, axes = plt.subplots(1, 3, figsize=(12, 10))# 绘制每个聚类的分割图像
for i, ax in enumerate(axes.flat):ax.imshow(segmented_image_list[i])  # 显示分割后的图像ax.set_title(f'Cluster {i+1}', fontsize=14)  # 设置标题为聚类编号ax.axis('off')  # 禁用坐标轴# 调整布局,防止重叠
plt.tight_layout()
plt.show()

download


5.3 异常检测

K-means算法也可用于异常检测,尤其是在数据集中存在噪声或异常点时。通过计算数据点到簇中心的距离,可以识别那些远离簇中心的点作为异常点。这些异常点可能代表了异常行为或错误数据。

5.3.1 生成原始数据集并可视化

from sklearn.cluster import KMeans
import numpy as np
from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt
import seaborn as sns# 设置主题和字体
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})# 生成模拟数据:两个明显簇和少量离群点
np.random.seed(42)
cluster_1 = np.random.normal(loc=[5, 5], scale=1.5, size=(100, 2))
cluster_2 = np.random.normal(loc=[15, 15], scale=1.5, size=(100, 2))
outliers = np.random.uniform(low=[0, 0], high=[20, 20], size=(10, 2))
X = np.vstack([cluster_1, cluster_2, outliers])# 可视化样本
plt.figure(figsize=(8, 6))
x = X[:, 0]
y = X[:, 1]
plt.scatter(x, y, s=20, c='gray', alpha=0.7, label='数据点')
plt.title("数据点分布图", fontsize=16)
plt.xlabel("X轴", fontsize=12)
plt.ylabel("Y轴", fontsize=12)
plt.grid(color='gray', linestyle='--', linewidth=0.8, alpha=0.3)  # 添加网格线样式
plt.legend()
plt.show()

download

5.3.2 聚类并进行异常值比较

# KMeans算法拟合
kmeans_model = KMeans(n_clusters=2, random_state=42).fit(X)# 聚类中心
centroids = kmeans_model.cluster_centers_# 每个样本到聚类中心的欧式距离
D = cdist(X, centroids, 'euclidean')# 每个样本的最近聚类中心索引
cluster_labels = D.argmin(axis=1)# 每个样本到所属聚类中心的距离
distances_to_cluster = np.min(D, axis=1)# 设置异常点的距离阈值
threshold = 4.0# 异常点判定:仅比较点与其所属簇中心的距离
outliers = X[distances_to_cluster > threshold]

array([[15.77257153, 20.77909724],
[18.47198785, 12.19910221],
[10.13809899, 13.46341854],
[18.19955006, 12.0718683 ],
[ 1.12750993, 17.29444753],
[16.25802018, 19.99435347],
[19.93273674, 11.10863411],
[16.99294781, 4.94696203],
[ 9.01088271, 2.5831883 ],
[19.08102055, 12.12349269],
[ 4.57285611, 13.43401369],
[12.36256481, 7.16325436]])

5.3.3 可视化异常值检测结果

# 可视化
plt.figure(figsize=(10, 8))# 绘制簇的点
palette = sns.color_palette("husl", 2)
for i in range(2):  # 遍历每个簇plt.scatter(X[cluster_labels == i, 0], X[cluster_labels == i, 1], s=50, color=palette[i], alpha=0.7, label=f"簇 {i+1}", edgecolor='k', marker='o')# 绘制聚类中心
plt.scatter(centroids[:, 0], centroids[:, 1], s=200, c='red', marker='x', label='聚类中心')# 绘制离群点
if len(outliers) > 0:plt.scatter(outliers[:, 0], outliers[:, 1], s=100, c='red', label='离群点', edgecolor='k', zorder=6)# 绘制分界线
for center in centroids:circle = plt.Circle(center, threshold, color='gray', alpha=0.3, fill=True, linestyle='--')plt.gca().add_artist(circle)# 图表设置
plt.title("KMeans 聚类与优化后的异常值检测", fontsize=16)
plt.xlabel("X轴", fontsize=12)
plt.ylabel("Y轴", fontsize=12)
plt.grid(color='gray', linestyle='--', linewidth=0.8, alpha=0.3)  # 添加网格线样式
plt.legend(loc='upper left', fontsize=10)
plt.tight_layout()
plt.show()

请添加图片描述


http://www.mrgr.cn/news/83194.html

相关文章:

  • 【简单了解一下深度学习】
  • 玄机-第一章 应急响应-webshell查杀的测试报告
  • GAN的应用
  • STM32-WWDG/IWDG看门狗
  • 自动驾驶相关知识学习笔记
  • matlab专栏-常见问题处理
  • 第四、五章图论和网络爬虫+网络搜索
  • python虚拟环境的使用
  • C# 对象和类型(结构)
  • ArrayList和HashMap区别
  • 2025新年源码免费送
  • 【JavaEE进阶】获取Cookie/Session
  • 强化学习入门
  • 【C++】16.stack和queue的使用
  • 【TI毫米波雷达】DCA1000不使用mmWave Studio的数据采集方法,以及自动化实时数据采集
  • UI自动化测试保姆级教程--pytest详解(精简易懂)
  • halcon三维点云数据处理(六)find_box_3d
  • 创建Java项目,并添加MyBatis包和驱动包
  • VSCode 中的 launch.json 配置使用
  • 腾讯云AI代码助手编程挑战赛-学习助手
  • Node.js中的fs模块:文件与目录操作(写入、读取、复制、移动、删除、重命名等)
  • 消息队列MQ(二)
  • C语言初阶习题【25】strcpy的模拟实现
  • ubuntu编译安装libvirt
  • 深度学习与计算机视觉 (博士)
  • 如何让用户在网页中填写PDF表格?