算法——K-means算法和算法改进

简介:个人学习分享,如有错误,欢迎批评指正。

一、什么是K-means算法?

K-means算法是一种无监督的聚类算法,用于将一组数据点分为K个簇(cluster)。其核心目标是将数据点划分到K个不同的簇中,使得每个簇内的数据点之间的相似性最大化,而不同簇之间的相似性最小化

具体而言,K-means算法通过以下方式实现聚类:

  1. 簇中心(质心):每个簇都有一个中心点,称为质心(centroid)。质心通常是该簇中所有数据点的平均值。
  2. 距离度量:数据点与质心之间的距离通常使用欧几里得距离度量。每个数据点被分配到与其最近的质心所在的簇中。
  3. 目标函数:K-means算法的目标是最小化所有数据点到其所属簇质心的距离平方和,这个值被称为簇内平方和误差(Within-Cluster Sum of Squares, WCSS)。

通过反复更新数据点的分配和质心的位置,K-means算法不断优化簇的划分,最终得到K个簇,使得簇内数据点之间更加相似,簇间差异更大。

在这里插入图片描述

牧师-村民模型

  • 有四个牧师去郊区布道,一开始牧师们随意选了几个布道点,并且把这几个布道点的情况公告给了郊区所有的村民,于是每个村民到离自己家最近的布道点去听课。
    听课之后,大家觉得距离太远了,于是每个牧师统计了一下自己的课上所有的村民的地址,搬到了所有地址的中心地带,并且在海报上更新了自己的布道点的位置。
    牧师每一次移动不可能离所有人都更近,有的人发现A牧师移动以后自己还不如去B牧师处听课更近,于是每个村民又去了离自己最近的布道点……
    就这样,牧师每个礼拜更新自己的位置,村民根据自己的情况选择布道点,最终稳定了下来。
    我们可以看到该牧师的目的是为了让每个村民到其最近中心点的距离和最小。

二、K-近邻算法流程

1.初始化

  • 确定K值:设定簇的数量K,这个值通常需要根据数据的特性或通过经验确定。
  • 随机选择初始质心:从数据集中随机选择K个点作为初始质心,也可以通过如K-means++等方法选择更好的初始质心,以提高聚类效果。

2.分配数据点到最近的质心

  • 计算距离:对于数据集中每个数据点,计算它与K个质心之间的距离。通常使用欧几里得距离计算,即:
    d ( x i , μ j ) = ∑ m = 1 M ( x i m − μ j m ) 2 d(x_i, \mu_j) = \sqrt{\sum_{m=1}^{M}(x_{im} - \mu_{jm})^2} d(xi,μj)=m=1M(ximμjm)2

其中, x i x_i xi 是数据点, μ j \mu_j μj 是第 j j j 个质心, M M M 是数据点的维度。

  • 分配数据点:将每个数据点分配到距离其最近的质心所属的簇。

3.更新质心

  • 计算新的质心:对于每一个簇,计算其所有数据点的平均值,并将该平均值作为新的质心。计算公式为:

μ j = 1 ∣ C j ∣ ∑ x i ∈ C j x i \mu_j = \frac{1}{|C_j|} \sum_{x_i \in C_j} x_i μj=Cj1xiCjxi

其中, C j C_j Cj 是第 j j j 个簇中的所有数据点, μ j \mu_j μj 是该簇的质心。

4. 迭代
重复步骤2和3:继续将数据点分配到最近的质心,然后更新质心的位置。这个过程不断迭代,直到质心的位置不再发生显著变化,或者达到预定的迭代次数。
5. 收敛
收敛判断:当质心的位置在两次迭代间变化非常小时,或者所有数据点的分配不再变化,算法停止迭代,认为已经收敛。
6. 输出结果
输出簇和质心:算法最终输出每个数据点的簇标签,以及每个簇的质心位置。

伪代码

获取数据 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 为迭代次数,k 为簇的数目,n 为样本点数,m 为样本点维度。
空间复杂度 O ( m ( n + k ) O(m(n+k) O(m(n+k) ,其中,k 为簇的数目,m 为样本点维度,n 为样本点数。

三、K-means算法的损失函数和收敛问题

1. 损失函数

K-means算法的目标是将数据点划分为K个簇,使得每个簇内的数据点到该簇中心(质心)的距离之和最小。这个优化目标可以通过一个损失函数来表示,该损失函数通常称为“簇内平方和误差”(Within-Cluster Sum of Squares, WCSS),也可以称为“惯性”(Inertia)。

损失函数的定义

对于给定的K个簇 { C 1 , C 2 , … , C K } \{C_1, C_2, \ldots, C_K\} { C1,C2,,CK},每个簇的质心为 μ k \mu_k μk,K-means算法的损失函数 J J J 定义为:

J = ∑ k = 1 K ∑ x i ∈ C k ∥ x i − μ k ∥ 2 J = \sum_{k=1}^{K} \sum_{x_i \in C_k} \|x_i - \mu_k\|^2 J=k=1KxiCkxiμk2

其中:

  • x i x_i xi 是数据集中的第 i i i 个数据点。
  • μ k \mu_k μk 是簇 C k C_k Ck 的质心,等于该簇中所有数据点的均值。
  • ∥ x i − μ k ∥ \|x_i - \mu_k\| xiμk 是数据点 x i x_i xi 到簇中心 μ k \mu_k μk 的欧几里得距离。

损失函数的意义
这个损失函数衡量了数据点到其所属簇中心的距离的平方和,目标是最小化这个值,使得每个簇内的点尽可能地接近其簇中心。损失函数的最小化意味着簇内数据点的紧密性最大化,从而实现有效的聚类。

2. 收敛问题

K-means算法通过迭代来最小化损失函数,收敛性是指算法最终会停止在一个局部最优点,即簇中心和数据点的分配不再发生显著变化。K-means算法的收敛性是保证其能在有限次迭代后终止的关键。

收敛的过程
K-means算法的迭代过程可以总结为以下步骤:

  1. 初始化:随机选择K个点作为初始质心。
  2. 分配数据点:将每个数据点分配到最近的质心所属的簇。
  3. 更新质心:计算每个簇的新的质心(即所有簇内数据点的均值)。
  4. 检查收敛:如果质心的位置不再发生变化,或者变化小于设定的阈值,则认为算法收敛。

K-means算法的收敛性主要体现在以下几个方面:

  1. 有限次迭代收敛:由于每次迭代都会减少或保持损失函数的值,且可能的簇分配组合有限,K-means算法在有限次迭代后必定会收敛。
  2. 局部最优解:由于K-means是基于贪心策略的算法,它可能会收敛到局部最优解,而非全局最优解。最终的簇分配可能依赖于初始质心的选择。
  3. 初始值敏感性:K-means对初始质心的位置非常敏感。不同的初始化可能导致算法收敛到不同的局部最优点。因此,常常使用如K-means++的方法来改善初始质心选择,增加算法收敛到全局最优解的可能性。
  4. 停机条件:K-means通常设置两种停机条件:质心的变化小于某个阈值或达到最大迭代次数。两者之一满足时,算法停止。

数学解释收敛性
从数学角度看,K-means算法每次迭代都是在最小化一个分段线性但非连续的损失函数。由于每次迭代都会减少或保持损失函数的值,并且损失函数的取值是有限的,因此K-means算法在有限次迭代后必定会收敛。每次迭代后,新的簇分配和质心计算结果会维持或减小损失函数的值,直到算法停止变化,达成局部收敛。

四、k-means算法的调优与改进

K-means算法虽然简单有效,但也存在一些局限性。为了提高其性能,研究者和实践者提出了多种调优与改进方法。以下是常见的K-means算法的调优与改进策略:

1. 初始质心选择的改进

1.1.K-means++

K-means++是对传统K-means算法的一种改进,旨在解决K-means对初始质心选择敏感的问题。传统的K-means算法随机选择初始质心,这可能导致糟糕的聚类效果,尤其是当初始质心选择不佳时,可能会陷入局部最优解。K-means++通过更合理的初始质心选择策略,显著提高了K-means算法的收敛速度和聚类效果。

K-means++的核心思想是通过一种概率方法选择初始质心,使得质心能够更好地覆盖数据分布。它通过以下步骤来选择初始质心:

  1. 随机选择第一个质心

    • 从数据集中随机选择一个点作为第一个质心。
  2. 为后续质心选择分配概率

    • 对于数据集中每个剩余的点,计算其到最近已选择质心的距离平方,记为 D ( x ) 2 D(x)^2 D(x)2
    • 通过距离平方 D ( x ) 2 D(x)^2 D(x)2 的值来决定点被选为下一个质心的概率。距离较远的点(与已选择的质心)有更大的概率被选为下一个质心。
  3. 选择下一个质心

    • 根据步骤2计算出的概率分布,随机选择一个点作为下一个质心。
  4. 重复

    • 重复步骤2和3,直到选出 K K K 个质心为止。
  5. 执行标准K-means算法

    • 使用K-means++选出的初始质心,执行标准的K-means算法,进行数据点的分配和质心的更新,直到算法收敛。

K-means++的Python代码实现

  1. 调包实现(使用scikit-learn库)
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

# 生成随机数据
X = np.random.rand(100, 2)

# 使用K-means++初始化的K-means模型
kmeans = KMeans(n_clusters=3, init='k-means++', random_state=0)

# 进行聚类
kmeans.fit(X)

# 获取聚类结果
labels = kmeans.labels_
centers = kmeans.cluster_centers_

# 可视化聚类结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='x')
plt.title('K-means Clustering with K-means++ Initialization')
plt.show()

  1. 不调包实现
    以下是K-means++算法的手动实现版本:
import numpy as np
import matplotlib.pyplot as plt

def initialize_centroids_kmeans_plus_plus(X, k):
    # 随机选择第一个质心
    centroids = [X[np.random.choice(X.shape[0])]]
    
    for _ in range(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值