K-means 算法原理

Posted ITAK

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K-means 算法原理相关的知识,希望对你有一定的参考价值。

1. 聚类

K-means算法是一种常用的聚类算法,所谓的聚类就是指给定 N N N个样本的数据集,需要构造 k k k 个簇(类),使得这 k k k 个簇之间的关系最小。

2. K-means算法基本步骤

  1. 随机初始化 k k k个点,作为聚类中心
  2. 在第 i i i次迭代中,对于每个样本点,选取距离最近的聚类中心,归为该类
  3. 遍历一遍之后,更新聚类中心,其中更新规则为:聚类中心取当前类的平均值
  4. 重复步骤2、3,直到满足迭代次数,或者聚类状态不发生改变

3. 算法优化

3.1 轮廓系数

轮廓系数(Silhouette Coefficient)结合了聚类的凝聚度(Cohesion)和分离度(Separation),用于评估聚类的效果。该值处于 [ − 1 , 1 ] [-1,1] [1,1]之间,值越大,表示聚类效果越好。具体计算方法如下:

  1. 对于每个样本点 i i i,计算点 i i i与其同一个簇内的所有其他元素距离的平均值,记作 a ( i ) a(i) a(i),用于量化簇内的凝聚度。
  2. 选取i外的一个簇 b b b,计算 i i i b b b中所有点的平均距离,遍历所有其他簇,找到最近的这个平均距离,记作 b ( i ) b(i) b(i),即为 i i i的邻居类,用于量化簇之间分离度。
  3. 对于样本点 i i i ,轮廓系数 s ( i ) = b ( i ) – a ( i ) m a x a ( i ) , b ( i ) s(i) = \\frac b(i) – a(i) max\\a(i),b(i)\\ s(i)=maxa(i),b(i)b(i)a(i)
  4. 计算所有i的轮廓系数,求出平均值即为当前聚类的整体轮廓系数,度量数据聚类的紧密程度

3.2 K值的选择

方法一:轮廓系数法

可以通过枚举的方法,令 k k k 2 2 2 10 10 10(随便的一个固定值,但不能太大),对于每一个 k k k 值进行 K-means 算法,然后取轮廓系数最大的那个 k k k 作为最终聚类的簇的数目。

方法二:误差平方和法

定义误差平方和公式如下:
S S E = ∑ i = 1 k ∑ d ∈ C i ∣ d − c e n t e r i ∣ 2 SSE = \\sum_i=1^k\\sum_d\\in C_i |d-center_i|^2 SSE=i=1kdCidcenteri2
其中 C i C_i Ci 是第 i i i 个簇,其中 d d d 是 簇 C i C_i Ci 的样本, c e n t e r i center_i centeri 是第 i i i 个簇的聚类中心
随着聚类数 k k k 的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且,当k小于真实聚类数时,由于 k k k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当 k k k到达真实聚类数时,再增加 k k k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着 k k k值的继续增大而趋于平缓,也就是说SSE和 k k k的关系图是一个手肘的形状,而这个肘部对应的 k k k值就是数据的真实聚类数。–转自手肘法理论

3.3 初始点的选择

  1. 从给定的样本集合中随机选择一个样本作为第一个聚类中心
  2. 然后对于样本集合中的每一个样本点 x x x,计算离该样本 x x x与最近的聚类中心的距离 D ( x ) D(x) D(x)
  3. 概率的选择D(x)较大的点作为新的样本中心
  4. 重复步骤2和3,直到聚类中心达到 k k k 个为止

4. 代码

以鸢尾花数据为例,下面是k-means的代码

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
# 加载数据
def loadData():
    iris = load_iris()
    #print(iris)
    X = np.array(iris.data[:])
    #print(X.shape)
    # 以鸢尾花后两个特征作为聚类特征
    # plt.scatter(X[:, 2], X[:, 3], c="red", marker='o', label='two features')
    # plt.xlabel('petal length')
    # plt.ylabel('petal width')
    # plt.legend(loc=2)
    # plt.show()
    return X[:,2:]
# 第一次随机获取k个中心点
def getCenterPoints(X, k):
    m, n = X.shape
    centerPoints = np.zeros((k, n))
    for i in range(k):
        id = int(np.random.uniform(0, m))
        centerPoints[i, :] = X[id, :]
    return centerPoints

#得到两个数据点之间的欧氏距离
def getDis(x, y):
    return np.sqrt(np.sum((x - y) **2 ))
# k-means算法
def KMeans(X, k):
    m = X.shape[0]
    cluster = np.mat(np.zeros((m, 2)))
    #1. 随机获取中心点
    centerPoints = getCenterPoints(X, k)
    for times in range(100):
        for i in range(m):
            minDist, minID = 1000000.0, -1
            for j in range(k):
                dis = getDis(X[i, :], centerPoints[j, :])
                if dis < minDist:
                    minDist, minID = dis, j
            #2.对于每个样本点,选取最近的中心点,归为该类
            cluster[i, :] = minID, minDist**2
        #3. 更新中心点
        for i in range(k):
            pointsInCluster = X[np.nonzero(cluster[:, 0].A == i)[0]]  # 获取簇类所有的点
            centerPoints[i, :] = np.mean(pointsInCluster, axis=0)  # 对矩阵的行求均值
    return centerPoints, cluster
#对聚类好的数据进行画图
def showCluster(X, k, cluster, centerPoints):
    m = X.shape[0]
    mark = ['or', 'ob', 'og']
    for i in range(m):
        markIndex = int(cluster[i, 0])
        plt.plot(X[i, 0], X[i, 1], mark[markIndex])
    mark = ['Dr', 'Db', 'Dg']
    # 绘制中心点
    for i in range(k):
        plt.plot(centerPoints[i, 0], centerPoints[i, 1], mark[i])
    plt.show()

def main():
    X, k = loadData(), 3
    centerPoints, cluster = KMeans(X, k)
    showCluster(X, k, cluster, centerPoints)
if __name__ == '__main__':
    main()

分类效果:

以上是关于K-means 算法原理的主要内容,如果未能解决你的问题,请参考以下文章

视觉机器学习------K-means算法

将 K-means 应用于 ASR 的 MFCC 系数

K均值聚类算法

K-Means聚类算法原理

K-Means聚类算法原理

K-Means聚类算法原理