【机器学习】K-means 聚类

K-means 是一种经典的非监督学习聚类算法,常用于数据划分和模式识别。其核心思想是将数据集划分为 ( k ) 个互斥的簇,每个簇由一个质心(簇中心)来代表。

本文将系统性讲解 K-means 的原理,从算法步骤推导到实现细节,逐步展示如何用 Numpy 实现 K-means 算法,最后使用 Scikit-Learn 库验证结果,并可视化最终的聚类效果。

K-means 的基本原理

K-means 主要包含以下步骤:

  1. 初始化:随机选择 ( k ) 个初始中心点。
  2. 分配簇:将数据集中每个点分配到距离最近的中心点所在的簇。
  3. 更新中心点:对每个簇计算新的质心,并将质心更新为簇中的点的均值。
  4. 重复:重复"分配簇"和"更新中心点"这两个步骤,直到质心不再变化或达到最大迭代次数。

K-means 算法旨在最小化每个数据点到其所属簇质心的欧氏距离平方和,即簇内误差平方和(Within-Cluster Sum of Squares, WCSS)

WCSS = ∑ i = 1 k ∑ x ∈ C i ∣ ∣ x − μ i ∣ ∣ 2 \text{WCSS} = \sum_{i=1}^{k} \sum_{x \in C_i} ||x - \mu_i||^2 WCSS=i=1∑kx∈Ci∑∣∣x−μi∣∣2

其中 ( C_i ) 表示第 ( i ) 个簇,( \mu_i ) 表示第 ( i ) 个簇的质心。

用 Numpy 实现 K-means 算法

数据生成与初始化

首先,我们生成一组模拟数据以便后续聚类实验使用。这里我们生成三个簇,每个簇中心在不同的位置。

python 复制代码
import numpy as np
import matplotlib.pyplot as plt

# 生成模拟数据
np.random.seed(0)
cluster_1 = np.random.randn(100, 2) + np.array([5, 5])
cluster_2 = np.random.randn(100, 2) + np.array([-5, -5])
cluster_3 = np.random.randn(100, 2) + np.array([5, -5])

# 合并数据
X = np.vstack((cluster_1, cluster_2, cluster_3))

# 绘制数据
plt.scatter(X[:, 0], X[:, 1], s=30)
plt.title("原始数据")
plt.show()

K-means 算法实现

接下来,我们实现 K-means 算法的每个步骤。

初始化质心

随机选择 ( k ) 个点作为初始质心。

python 复制代码
def initialize_centroids(X, k):
    np.random.seed(0)
    random_indices = np.random.permutation(X.shape[0])
    centroids = X[random_indices[:k]]
    return centroids
计算距离并分配簇

计算每个点到质心的欧氏距离,并将其分配到最近的簇。

python 复制代码
def compute_distances(X, centroids):
    distances = np.zeros((X.shape[0], len(centroids)))
    for i, centroid in enumerate(centroids):
        distances[:, i] = np.linalg.norm(X - centroid, axis=1)
    return distances

def assign_clusters(X, centroids):
    distances = compute_distances(X, centroids)
    return np.argmin(distances, axis=1)
更新质心

根据每个簇的所有点重新计算质心。

python 复制代码
def update_centroids(X, labels, k):
    centroids = np.zeros((k, X.shape[1]))
    for i in range(k):
        cluster_points = X[labels == i]
        if len(cluster_points) > 0:
            centroids[i] = cluster_points.mean(axis=0)
    return centroids
K-means 主循环

整合上述函数,将它们放入一个循环中实现完整的 K-means 算法。

python 复制代码
def kmeans(X, k, max_iters=100, tolerance=1e-4):
    centroids = initialize_centroids(X, k)
    for i in range(max_iters):
        old_centroids = centroids
        labels = assign_clusters(X, centroids)
        centroids = update_centroids(X, labels, k)
        
        # 检查质心是否收敛
        if np.all(np.abs(centroids - old_centroids) < tolerance):
            break
    return centroids, labels

运行 K-means 算法

运行 K-means 算法并可视化聚类结果。

python 复制代码
# 设置簇数
k = 3
centroids, labels = kmeans(X, k)

# 可视化聚类结果
plt.scatter(X[:, 0], X[:, 1], c=labels, s=30, cmap="viridis")
plt.scatter(centroids[:, 0], centroids[:, 1], s=200, c="red", marker="X")
plt.title("K-means 聚类结果")
plt.show()

可视化 WCSS(簇内误差平方和)

为了确定最佳的簇数 ( k ),可以使用"肘部法则"观察 WCSS 随着 ( k ) 增加的变化。我们将计算不同簇数下的 WCSS 值,并绘制其趋势图。

python 复制代码
def calculate_wcss(X, centroids, labels):
    wcss = 0
    for i in range(len(centroids)):
        cluster_points = X[labels == i]
        wcss += np.sum((cluster_points - centroids[i]) ** 2)
    return wcss

# 计算不同 k 值下的 WCSS
wcss_values = []
for k in range(1, 10):
    centroids, labels = kmeans(X, k)
    wcss = calculate_wcss(X, centroids, labels)
    wcss_values.append(wcss)

# 绘制 WCSS 趋势图
plt.plot(range(1, 10), wcss_values, marker="o")
plt.xlabel("簇数 k")
plt.ylabel("簇内误差平方和 (WCSS)")
plt.title("肘部法则选择最优簇数")
plt.show()

通常,随着 ( k ) 增加,WCSS 会减小,但会在某个 ( k ) 值后趋于平稳。肘部法则通过选择 WCSS 曲线弯曲点的 ( k ) 值,帮助确定最合适的聚类数。

使用 Scikit-Learn 实现 K-means 聚类

Scikit-Learn 提供了 KMeans 类,可以快速应用 K-means 算法。下面我们将使用它来验证我们之前手动实现的聚类效果。

python 复制代码
from sklearn.cluster import KMeans

# 使用 Scikit-Learn 的 KMeans
kmeans_sklearn = KMeans(n_clusters=3, random_state=0)
kmeans_sklearn.fit(X)
labels_sklearn = kmeans_sklearn.labels_
centroids_sklearn = kmeans_sklearn.cluster_centers_

# 可视化 Scikit-Learn 的 K-means 聚类结果
plt.scatter(X[:, 0], X[:, 1], c=labels_sklearn, s=30, cmap="viridis")
plt.scatter(centroids_sklearn[:, 0], centroids_sklearn[:, 1], s=200, c="red", marker="X")
plt.title("Scikit-Learn K-means 聚类结果")
plt.show()

总结

本文详细介绍了 K-means 聚类算法的工作原理,手动实现了整个算法流程,包括初始化质心、分配簇、更新质心以及主循环,并可视化了聚类结果。为了选择最佳的簇数,我们还使用了肘部法则,绘制了不同簇数下的 WCSS。最后,我们通过 Scikit-Learn 库验证了手动实现的 K-means 效果并展示了聚类的可视化结果。

随机初始化质心可能导致 K-means 得到局部最优解,可以通过多次运行算法选取最佳模型。

相关推荐
Altair澳汰尔2 分钟前
数据分析和AI丨知识图谱,AI革命中数据集成和模型构建的关键推动者
人工智能·算法·机器学习·数据分析·知识图谱
call me by ur name26 分钟前
VLM--CLIP作分类任务的损失函数
人工智能·机器学习·分类
Python机器学习AI31 分钟前
分类模型的预测概率解读:3D概率分布可视化的直观呈现
算法·机器学习·分类
dwjf3211 小时前
机器学习(四)-回归模型评估指标
人工智能·机器学习·线性回归
电子海鸥3 小时前
迁移学习--fasttext概述
人工智能·机器学习·迁移学习
dwjf3213 小时前
机器学习(三)-多项式线性回归
人工智能·机器学习·线性回归
愚者大大7 小时前
优化算法(SGD,RMSProp,Ada)
人工智能·算法·机器学习
dundunmm7 小时前
数据挖掘之认识数据
人工智能·机器学习·信息可视化·数据挖掘
梁小憨憨8 小时前
机器学习(Machine Learning)的安全问题
人工智能·安全·机器学习