机器学习 K-means

K-means 聚类是一种常用的基于距离的聚类算法,旨在将数据集划分为 K 个簇。算法的目标是最小化簇内的点到簇中心的距离总和。

详细来源于:聚类分析算法——K-means聚类 详解-CSDN博客


1.原理和思想 

K-means 的目标是将数据集划分为 K 个簇(clusters),使得每个数据点属于距离最近的簇中心。通过反复调整簇中心的位置,K-means 不断优化簇内的紧密度,从而获得尽量紧凑、彼此分离的簇。

核心思想

  • 簇(Cluster):K-means 通过最小化簇内距离的平方和,使得数据点在簇内聚集。一个簇是数据点的集合,这些点在某种意义上“彼此相似”。比如,可以将商场顾客分为“学生群体”“上班族”“退休老人”这三个簇。
  • 簇中心(Centroid):簇中心是簇中所有点的平均值,表示簇的中心位置。
  • 簇分配和更新:K-means 通过反复迭代,调整簇的分配,使得簇内数据点与质心的距离尽可能小,逐步收敛。

2.工作流程 

2.1 核心思想

K-means 使用“最近距离”来分组:

  1. 随机选择 K 个质心(初始中心点)。
  2. 每个数据点分配到距离最近的质心所属的簇。
  3. 重新计算每个簇的质心。
  4. 重复步骤 2 和 3,直到质心不再变化(或达到指定的迭代次数)。

2.2 算法步骤(结合例子)
       

K-means 聚类的流程分为两个主要步骤:分配(Assignment)和更新(Update)。以下是详细步骤:

  1. 选择 K 值:设定簇的数量K 。即类别数
  2. 初始化簇中心:随机选择 K个数据点作为初始簇中心(centroids)。
  3. 分配步骤(Assignment Step):对于数据集中的每个点,将它分配到最近的簇中心对应的簇。这里的“距离”通常使用欧氏距离(Euclidean distance)。
  4. 更新步骤(Update Step):根据当前的簇分配,重新计算每个簇的中心,即计算簇内所有点的均值作为新的簇中心。
  5. 重复 3 和 4 步:不断重复分配和更新步骤,直到簇中心不再发生变化(收敛)或达到指定的最大迭代次数。

伪代码

KMeans(X, K):
    1. 随机选择 K 个点作为初始簇中心
    2. 重复以下步骤,直到簇中心不再发生变化:
        a. 分配每个点到最近的簇中心
        b. 重新计算每个簇的中心,作为簇内所有点的均值
    3. 返回最终的簇分配和簇中心

K-means 的优缺点

  • 优点
    • 简单高效:适合大规模数据,处理大数据集时非常高效,具有良好的伸缩性。
    • 收敛速度快:在适合的初始中心选择下,K-means 通常可以较快收敛。
  • 缺点
    • 对初始点敏感:初始簇中心的选择对最终结果影响较大。
    • 非凸形状簇(球形簇):K-means 假设每个簇是凸形且大小相近,不适合发现非凸形状的簇或大小差异很大的簇,如“月牙型”数据。
    • 对噪声敏感:离群点会影响簇的中心计算。
    • 局部最优:K-means不能保证全局最优,只能达到局部最优
    • 数据种类限制:算法要求样本存在均值,限制了数据的种类

代码

from sklearn.cluster import KMeans
import numpy as np
 
# 生成示例数据
X = np.array([[1, 2], [2, 2], [3, 3], [8, 7], [8, 8], [25, 80]])
 
# 初始化并训练 KMeans 模型
kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
 
# 获取簇标签和簇中心
labels = kmeans.labels_
centroids = kmeans.cluster_centers_
 
print("Cluster labels:", labels)
print("Centroids:", centroids)

手动实现: 

import numpy as np
 
def initialize_centroids(X, k):
    indices = np.random.choice(len(X), k, replace=False)
    return X[indices]
 
def closest_centroid(X, centroids):
    distances = np.linalg.norm(X[:, np.newaxis] - centroids, axis=2)
    return np.argmin(distances, axis=1)
 
def update_centroids(X, labels, k):
    return np.array([X[labels == i].mean(axis=0) for i in range(k)])
 
def kmeans(X, k, max_iters=100, tol=1e-4):
    centroids = initialize_centroids(X, k)
    for i in range(max_iters):
        labels = closest_centroid(X, centroids)
        new_centroids = update_centroids(X, labels, k)
        if np.all(np.abs(new_centroids - centroids) < tol):
            break
        centroids = new_centroids
    return labels, centroids
 
# 示例数据
X = np.array([[1, 2], [2, 2], [3, 3], [8, 7], [8, 8], [25, 80]])
 
# 运行 K-means
labels, centroids = kmeans(X, k=2)
print("最终簇:", labels)
print("质心位置:", centroids)

posted @ 2025-04-25 14:16  qinchaojie  阅读(235)  评论(0)    收藏  举报  来源