18、聚类算法——K-means家族

本文介绍了K-means聚类算法的历史、基本思想、流程,以及其在不同场景的应用,如客户细分和文本聚类。着重讨论了算法的局限性,如对初始聚类中心的敏感性和处理大规模数据的挑战,以及改进方法如K-Means++和K-means||。
摘要由CSDN通过智能技术生成

1 K-means家族简介

历史渊源 :虽然其思想能够追溯到1957年的Hugo Steinhaus,术语“k-均值”于1967年才被James MacQueen首次使用。标准算法则是在1957年被Stuart Lloyd作为一种脉冲码调制的技术所提出,但直到1982年才被贝尔实验室公开出版。在1965年,E.W.Forgy发表了本质上相同的方法,所以这一算法有时被称为Lloyd-Forgy方法。更高效的版本则被Hartigan and Wong提出(1975/1979)

给定一个有 M M M个对象的数据集,构建一个具有 k k k个簇的模型,其中 k ≤ M k \leq M kM。满足以下条件:

  • 每个簇至少包含一个对象
  • 每个对象属于且仅属于一个簇
  • 将满足上述条件的 k k k个簇成为一个合理的聚类划分

基本思想:对于给定的类别数目 k k k,首先给定初始划分,通过迭代改变样本和簇的隶属关系,每次处理后得到的划分方式比上一次的好(总的数据集之间的距离和变小了)

K-Means(K均值)算法是无监督的聚类算法,算法简单,聚类效果好,即使是在巨大的数据集上也非常容易部署实施。正因为如此,它在很多领域都得到的成功的应用,如市场划分、机器视觉、 地质统计学、天文学和农业等。K-Means算法有大量的变体,包括初始化优化K-Means++以及大数据应用背景下的k-means||和Mini Batch K-Means

2 算法流程

K-means算法,也称为K-平均或者K-均值,是一种使用广泛的最基础的聚类算法,一般作为掌握聚类算法的第一个算法

假设输入样本为 T = x 1 , x 2 , . . . , x m T=x_1,x_2,...,x_m T=x1,x2,...,xm;则算法步骤为(使用欧几里得距离公式):

  • 选择初始化的k个类别中心(质心) a 1 , a 2 , . . . a k a_1,a_2,...a_k a1,a2,...ak;

  • 对于每个样本 x i x_i xi,将其标记位距离类别中心 a j a_j aj最近的类别 j j j
    l a b e l i = arg ⁡ min ⁡ 1 ≤ j ≤ k ( x i − a j ) 2 label_i=\mathop {\arg \min }\limits_{1\leq j \leq k}\sqrt{(x_i-a_j)^2} labeli=1jkargmin(xiaj)2

  • 更新隶属每个类别中心点 a j a_j aj的所有样本的均值
    μ i = 1 ∣ C i ∣ ∑ x ∈ C i x \mu_i=\frac{1}{|C_i|}\sum_{x\in C_i}x μi=Ci1xCix

  • 重复上面两步操作,直到达到某个中止条件

终止条件:迭代次数、最小平方误差MSE、簇中心点变化率

K-Means算法的思想很简单,对于给定的样本集,按照样本之间的距离大小,将样本集划分为K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。

如果用数学表达式表示,假设簇划分为 ( C 1 , C 2 , . . . C k ) (C_1,C_2,...C_k) (C1,C2,...Ck),则我们的目标是最小化平方误差 E E E
E = ∑ i = 1 k ∑ x ∈ C i ∥ x − μ i ∥ 2 2 E = \sum\limits_{i = 1}^k {\sum\limits_{x \in {C_i}}^{} {\left\| {x - {\mu _i}} \right\|_2^2} } E=i=1kxCixμi22
其中 μ i μ_i μi是簇 C i C_i Ci的均值向量,有时也称为质心,表达式为:
μ i = 1 ∣ C i ∣ ∑ x ∈ C i x {\mu _i} = \frac{1}{{\left| {{C_i}} \right|}}\sum\limits_{x \in {C_i}}^{} x μi=Ci1xCix

获取数据 n 个 m 维的数据
随机生成 K 个 m 维的点
while(t)
    for(int i=0;i < n;i++)
        for(int j=0;j < k;j++)
            计算点 i 到类 j 的距离
    for(int i=0;i < k;i++)
        1. 找出所有属于自己这一类的所有数据点
        2. 把自己的坐标修改为这些数据点的中心点坐标
end
  • 时间复杂度: O ( t k n m ) O(tknm) O(tknm),其中, t t t 为迭代次数, k k k 为簇的数目, n n n 为样本点数, m m m 为样本点维度。
  • 空间复杂度: O ( m ( n + k ) ) O(m(n+k)) O(m(n+k)) ,其中, k k k 为簇的数目, m m m 为样本点维度, n n n 为样本点数。

3 直观理解

在这里插入图片描述

对数据集 X = n p . a r r a y ( [ [ 1 , 2 ] , [ 2 , 2 ] , [ 6 , 8 ] , [ 7 , 8 ] ] ) X = np.array([[1, 2], [2, 2], [6, 8],[7 ,8]]) X=np.array([[1,2],[2,2],[6,8],[7,8]])聚类, K = 2 K=2 K=2,初始聚类中心为 C = n p . a r r a y ( [ [ 1 , 2 ] , [ 2 , 2 ] ] ) C = np.array([[1, 2], [2, 2]]) C=np.array([[1,2],[2,2]])

要求:打印每次迭代聚类中心的位置

import numpy as np
X = np.array([[1, 2], [2, 2], [6, 8],[7 ,8]])
C = np.array([[1.0, 2.0], [2.0, 2.0]]) # 聚类中心
iters = 5  #迭代次数
while (iters>0) : # 遍历每一个聚类中心,计算样本到每个聚类中心的距离
    # 将样本分配到所属的聚类中心
    iters -= 1
    B = []
    for c in C: #获取每个簇的样本,求质心更新C
        dis = np.sqrt(((X - c)**2).sum(axis=1))
        B.append(dis)
    min_idx = np.argmin(np.array(B),axis=0)
    for i in range(len(C)):
        C[i] = np.mean(X[min_idx == i],axis=0)

# 打印所有样本的所属的簇
print(min_idx)

4 案例详解

定义:客户细分是一种市场策略,通过将潜在客户分为不同的组或段,企业可以更精准地进行产品推广或服务提供。

例子:一个在线零售商希望根据客户的年龄、购买历史和浏览行为来进行客户细分,以实施更有效的营销策略。

数据集说明

在本案例中,我们将使用一个简单的数据集,包括客户的年龄、购买频率和平均消费金额三个特征。

客户ID | 年龄 | 购买频率 | 平均消费金额
------|------|----------|--------------
1     | 25   | 5        | 50
2     | 30   | 3        | 40
3     | 35   | 1        | 20
...

Python实现代码

下面是使用Python和PyTorch来实现KMeans算法的代码。我们首先导入必要的库,然后进行数据准备、模型训练和结果可视化。

import numpy as np
import torch
import matplotlib.pyplot as plt

# 创建一个模拟数据集
data = torch.tensor([[25, 5, 50],
                     [30, 3, 40],
                     [35, 1, 20]], dtype=torch.float32)

# 初始化K个中心点
K = 2
centers = data[torch.randperm(data.shape[0])][:K]

# KMeans算法主体
for i in range(10):  # 迭代10次
    # 步骤2:计算每个点到各个中心点的距离,并分配到最近的中心点
    distances = torch.cdist(data, centers)
    labels = torch.argmin(distances, dim=1)

    # 步骤3:重新计算中心点
    for k in range(K):
        centers[k] = data[labels == k].mean(dim=0)

# 结果可视化
plt.scatter(data[:, 0], data[:, 1], c=labels)
plt.scatter(centers[:, 0], centers[:, 1], marker='x')
plt.show()

5 KMeans在文本聚类中的应用

除了常见的数值数据聚类,KMeans也被广泛应用于文本数据的聚类。在这一节中,我们将探讨KMeans在文本聚类中的应用,特别是在自然语言处理(NLP)领域。

文本向量化

  • 定义:文本向量化是将文本数据转化为数值形式,以便机器学习算法能更容易地处理它。
  • 例子:例如,一个常用的文本向量化方法是TF-IDF(Term Frequency-Inverse Document Frequency)。

KMeans与TF-IDF

  • 定义:结合TF-IDF和KMeans算法可以有效地对文档进行分类或主题建模。
  • 例子:一个新闻网站可能有成千上万的文章,它们可以通过应用KMeans聚类算法与TF-IDF来分类成几大主题,如“政治”、“科技”、“体育”等。

Python实现代码

下面的代码使用Python的sklearn库进行TF-IDF文本向量化,并应用KMeans进行文本聚类。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans

# 模拟文本数据
documents = ["政治新闻1", "科技新闻1", "体育新闻1",
             "政治新闻2", "科技新闻2", "体育新闻2"]

# TF-IDF向量化
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(documents)

# KMeans聚类
model = KMeans(n_clusters=3)
model.fit(X)
labels = model.labels_

# 输出与解释
for i, label in enumerate(labels):
    print(f"文档 {documents[i]} 被归类到 {label} 集群。")
'''
文档 政治新闻1 被归类到 0 集群。
文档 科技新闻1 被归类到 1 集群。
文档 体育新闻1 被归类到 2 集群。
文档 政治新闻2 被归类到 0 集群。
文档 科技新闻2 被归类到 1 集群。
文档 体育新闻2 被归类到 2 集群。
'''

6 K-means衍生算法

6.1 K-means缺点

  • 缺点一:聚类中心的个数 K K K需要事先给定,但在实际中 K K K值的选定是非常困难的,很多时候我们并不知道给定的数据集应该聚成多少个类别才最合适

  • 缺点二:k-means算法需要随机地确定初始聚类中心,不同的初始聚类中心可能导致完全不同的聚类结果,有可能导致算法收敛很慢甚至出现聚类出错的情况

在这里插入图片描述

  • 针对第一个缺点:很难在k-means算法以及其改进算法中解决,一般来说,我们会根据对数据的先验经验选择一个合适的 k k k值,如果没有先验知识,则可以通过“肘方法”选择一个合适的 k k k

  • 针对第二个缺点:可以通过k-means++算法来解决

手肘法的核心指标是SSE(sum of the squared errors,误差平方和)
S S E = ∑ i = 1 k ∑ x ∈ C i ∥ x − μ i ∥ 2 SSE = \sum\limits_{i = 1}^k {\sum\limits_{x \in {C_i}}^{} {\left\| {x - {\mu _i}} \right\|_{}^2} } SSE=i=1kxCixμi2
其中, C i C_i Ci是第 i i i个簇, x x x C i C_i Ci中的样本点, μ i μ_i μi C i C_i Ci的质心( C i C_i Ci中所有样本的均值),SSE是所有样本的聚类误差,代表了聚类效果的好坏。

在这里插入图片描述

手肘法的核心思想是:随着聚类数 k k k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且, k k k小于真实聚类数时,由于k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当k到达真实聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的 k k k值就是数据的真实聚类数。当然,这也是该方法被称为手肘法的原因。

6.2 K-means++

针对K-Means算法对初始簇心比较敏感的问题,K-Means算法使用随机给定的方式,K-Means++算法采用下列步骤给定 k k k个初始质点,使初始的聚类中心之间的相互距离要尽可能远:

  1. 从数据集中任选一个节点作为第一个聚类中心 c 1 c_1 c1
  2. 计算每个样本点 x x x到当前已有聚类中心点之间的最短距离 D ( x ) D(x) D(x)(即与最近的一个聚类中心的距离);接着计算每个样本被选为下一个聚类中心的概率 D ( x ) 2 ∑ x ∈ X D ( x ) 2 \frac{D(x)^2}{\sum_{x \in X}D(x)^2} xXD(x)2D(x)2;最后按照轮盘发选择出下一个聚类中心。(距离已有聚类中心较远的一个点成为新增聚类中心点)
  3. 重复步骤2直到找到 k k k个聚类中心点

缺点:k-means++ 最主要缺点在于其内在的顺序执行特性,得到 k k k 个聚类中心必须遍历数据集 k k k 次,并且当前聚类中心的计算依赖于前面得到的所有聚类中心(第 k k k个聚类中心点的选择依赖前 k − 1 k-1 k1个聚类中心点的值),这使得算法无法并行扩展,极大地限制了算法在大规模数据集上的应用。

所以,在此基础上,提出了 K-means|| 算法

6.3 K-means||

k-means||改变了每次遍历时的取样规则,并非按照K-Means++算法每次遍历只获取1个样本,而是每次获取 k k k个样本,重复该取样操作 O ( log ⁡ n ) O(\log n) O(logn)次,然后再将这些抽样出的样本聚类出 k k k个点,最后使用这 k k k个点作为K-Means算法的初始聚簇中心点。实践证明:一般5次重复采用就可以保证一个比较好的聚簇中心点 。

k-means||是k-means++的变体,k-means||在初始化中心点时对kmeans++的缺点做了规避,主要体现在不需要根据k的个数严格地寻找k个点,突破了算法在大规模数据集上的应用瓶颈,同时初始化的中心点更加健壮。

6.4 K means对比

K meansK means ++K means ||
初始中心选择随机选择k个依次有序选择k个多次重复抽取样本子集,从中得到k个中心
Moderate size Large size data非常慢

7 小结

  • 优点:

    • 原理比较简单,实现也是很容易,收敛速度快
    • 聚类效果较优
    • 算法的可解释度比较强
    • 主要需要调参的参数仅仅是簇数 k k k
  • 缺点:

    • 不能处理如图情况
    • 采用迭代方法,得到的结果只是局部最优。
    • 对噪音和异常点比较的敏感。

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

healed萌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值