零基础学习Kmeans聚类算法的原理与实现过程

内容导入:

聚类是无监督学习的典型例子,聚类也能为企业运营中也发挥者巨大的作用,比如我们可以利用聚类对目标用户进行群体分类,把目标群体划分成几个具有明显特征区别的细分群体,从而可以在运营活动中为这些细分群体采取精细化、个性化的运营和服务;还可以利用聚类对产品进行分类,把企业的产品体系进一步细分成具有不同价值、不同目的的多维度的产品组合,在此基础分别制定和相应的开发计划、运营计划和服务规划。这都将提升运营的效率和商业效果。

聚类方法分为基于划分的聚类、基于层次的聚类、基于密度的聚类、基于网络的聚类、基于模型的聚类以及基于模糊的聚类,今天我们就从基于划分的聚类开始讲解聚类算法,什么是基于划分的聚类呢?其原理即需要将一堆散点进行聚类,聚类目标是“类内的点足够近,类间的点足够远”,而你需要做的就是(1)确定聚类数目;(2)挑选初始中心点;(3)迭代重置中心点直到满足“类内的点足够近,类间的点足够远”,典型的基于划分的聚类就是K-means算法。

K-means算法流程
经典的K-means算法

假设要将无标签数据集:

聚成k个簇C1,C2,…, Ck,最小化损失函数:

但是完成这个过程需要遍历所有可能的簇划分,这将带来大量的计算,而K-means是利用贪心策略求得近似解的方法,经典K-means算法流程如下:

(1)随机地选择k个对象,每个对象初始地代表了一个簇的中心;

(2)对剩余的每个对象,根据其与各簇中心的距离,将它赋给最近的簇;

(3)重新计算每个簇的平均值,更新为新的簇中心;

(4)不断重复2、3,直到达到某个终止条件。

这个终止条件可以是:没有(或最小数目)对象被重新分配给不同的聚类、没有(或最小数目)聚类中心再发生变化、误差平方和局部最小。

K-means算法的改进K-means++算法

因K-means算法的聚类结果会受到初始点的的选取的影响,有人提出了K-means++改进了初始点的选取过程:

(1)随机选取一个样本点作为第一个聚类中心

(2)计算每个样本点与当前已有聚类中心的最短距离,即:

则某样本点选为下一个簇中心的概率为

python实现K-means

在scikit-learn中的KMeans类实现了这一算法,下面我们来简单介绍一下Kmeans类的主要参数及方法:

KMeans的主要参数

n_clusters:int,可选,默认值8,行成的簇数以及中心数

init:{'k-means ++','random'或ndarray},默认值'k-means ++'

'k-means ++':以'k-means ++'方法选择初始中心

'random':随机选择初始中心

ndarray (nclusters, nfeatures):给定初始中心

n_init:int ,默认值 10,用不同的初始化质心运行算法的次数

max_iter : int, 默认值 300,最大的迭代次数

tol:float,默认值 1e-4 与inertia结合来确定收敛条件。

precompute_distances : {'auto', True, False},预计算距离,计算速度更快但占用更多内存。

'auto':如果 样本数乘以聚类数大于 12million 的话则不预计算距离。

True:总是预先计算距离。

False:永远不预先计算距离。

random_state : int, RandomState instance 或者None (默认), 确定质心初始化的随机数生成。使用整数使随机性具有确定性。

copy_x:boolean,默认值True 。当我们precomputing distances时,将数据中心化会得到更准确的结果。

True,原始数据不会被改变,确保X是C连续的

False,修改原始数据,并在函数返回之前放回原始数据,但是可能会通过减去然后加上数据均值来引入较小的数值差异,在这种情况下,也不会确保数据是C连续的,这可能会导致 大幅放缓。

n_jobs:int, 指定计算所用的进程数。内部原理是同时进行n_init指定次数的计算。

'None':除非在:obj:joblib.parallel_backend上下文中,否则表示1。

'-1': means using all processors.

algorithm : "auto", "full" or "elkan", 默认="auto"

'full': 经典的EM风格算法

'elkan':使用三角不等式的'elkan'会更有效,但不支持稀疏数据

'auto':密集数据选择'elkan',为稀疏数据选择'full'。

KMeans的主要方法

fit:训练Kmeans聚类

fit_predict:计算聚类中心并预测每个样本的聚类索引。

predict:预测,依据与聚类中心的远近进行类别预测

KMeans聚类实例:

本文仅展现聚类的过程及代码,可视化的代码不再展现

为了更好的可视化聚类效果,我们使用如下图所示的二维数据进行聚类:

Kmeans最优聚类数目的确定

我们知道Kmeans方法需要我们给出聚类数目,但是一般情况下我们无法直接给出一个很合适的聚类数目,因此我们需要确定最优的聚类数目,常见的确定最优聚类数的方法有手肘法和轮廓系数法。

下面我们就来介绍一下这两个方法的思想以及python实现确认最优聚类数目的过程。

手肘法:定义聚类的误差平方和

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

python计算不同聚类数目下误差平方和的代码如下:

SSE = []

for i in range(1,8):

km=KMeans(n_clusters=i)

km.fit(x)

y1=km.predict(x)

SSE.append(km.inertia_)

print("k="+str(i)+"时Kmeans的误差平方和:",km.inertia_)

'''

输出结果:

k=1时Kmeans的误差平方和: 9289.822973786537

k=2时Kmeans的误差平方和: 4081.729006176964

k=3时Kmeans的误差平方和: 2049.521363130263

k=4时Kmeans的误差平方和: 1258.109982411505

k=5时Kmeans的误差平方和: 1030.7046088439135

k=6时Kmeans的误差平方和: 891.9218511797383

k=7时Kmeans的误差平方和: 777.4389345859881

以聚类数目k为横坐标,误差平方和为纵坐标,绘制折线图如下图所示:

我们可以看到聚类数目到达4后,再增加k值,SSE下降幅度减小,SSE趋于平缓,所以我们可以确定聚类数目为4.

轮廓系数:轮廓系数的计算方法如下:

计算 a(i) = average(i向量到所有它属于的簇中其它点的距离),称为簇内不相似度

计算 b(i) = min (i向量到与它相邻最近的一簇内的所有点的平均距离),称为簇间不相似度

那么i向量轮廓系数就为:

所有点的轮廓系数的平均值,即聚类结果的总的轮廓系数。

轮廓系数的取值在[-1,1]之间,越趋近于1代表内聚度和分离度都相对较优,即聚类效果越好。(当簇内只有一点时,我们定义轮廓系数s(i)为0)

python计算不同聚类数目下轮廓系数的代码如下:

from sklearn import metrics

SC=[]

for i in range(2,8):

km=KMeans(n_clusters=i)

km.fit(x)

y1=km.predict(x)

sc=metrics.silhouette_score(x,y1)

SC.append(sc)

ch=metrics.calinski_harabaz_score(x,y1)

CH.append(ch)

print("k="+str(i)+"时Kmeans的轮廓系数:", sc)

'''

输出结果:

k=2时Kmeans的轮廓系数: 0.5104346420008198

k=3时Kmeans的轮廓系数: 0.5564101841418961

k=4时Kmeans的轮廓系数: 0.5707892750326952

k=5时Kmeans的轮廓系数: 0.47190247374410116

k=6时Kmeans的轮廓系数: 0.475091206758774

k=7时Kmeans的轮廓系数: 0.4198657590150086

以聚类数目k为横坐标,轮廓系数和为纵坐标,绘制折线图如下图所示:

我们可以看到k=4时轮廓系数最高,故最优聚类数目为4。

接下来我们在看一下不同聚类数目下的聚类的CH指标:

CH=[]

for i in range(2,8):

km=KMeans(n_clusters=i)

km.fit(x)

y1=km.predict(x)

ch=metrics.calinski_harabaz_score(x,y1)

CH.append(ch)

print("k="+str(i)+"时Kmeans的CH指标:", ch)

'''

输出结果:

k=2时Kmeans的CH指标: 1656.1868658421492

k=3时Kmeans的CH指标: 2290.942499540155

k=4时Kmeans的CH指标: 2757.8670074800625

k=5时Kmeans的CH指标: 2594.294350251559

k=6时Kmeans的CH指标: 2437.2529863724803

k=7时Kmeans的CH指标: 2359.025076485279

我们再看看之前介绍一个新的聚类的度量指标——CH指标,CH指标是数据集的分离度与紧密度的比值,以各类中心点与数据集的中心点的距离平方和来度量数据集的分离度,以类内各点与其类中心的距离平方和来度量数据的紧密度。聚类效果越好,类间差距应该越大,类内差距越小,即类自身越紧密,类间越分散,CH指标值越大聚类效果越好。

不同聚类数目下CH指标值的折线图如下:

从图中我们也可以发现聚类数目4的聚类效果最好,最后我们以最优聚类数目进行聚类,并可视化聚类结果如下图所示:

从图中我们可以看出数据被聚为四类,类内较紧密,类间较分散,聚类效果很好。(此时的误差平方和为:1258.109982,轮廓系数为:0.570789,CH指标为:2757.867)

K-means的优点与缺点
优点:对于大型数据集也是简单高效、时间复杂度、空间复杂度低。

缺点:数据集大时结果容易局部最优;需要预先设定K值,对最先的K个中心点选取很敏感;对噪声和离群值非常敏感;只用于数值型数据;不能解决非凸(non-convex)数据。

上一篇:机器学习深版08:EM算法


下一篇:机器学习系列(六) -- K-means算法 (食物数据集)