K-means聚类算法原理与实现

1,290 阅读6分钟

@[TOC]

无监督学习

首先这类算法是属于典型的无监督学习算法,比如 PCA 将维等等。这类算法在先前的机器学习文章过程中有提到,但是我自己没有去具体分析它的实现,只是简单地去使用sklearn去做一些应用去了。那么要先讲清楚K-means那么必然是要先搞清楚无监督的意思,我这里将使用最简单的语言来尽可能地去描述复杂算法(虽然这个K-means其实也不复杂,难的其实我认为还是对现实生活中各种参数的量化,建模,也就是如何得到合理高效的数据集。例如,如何寻找一个数据集来通过KNN算法来分析妹子对男孩子的喜好进行分类,女孩子喜欢男孩子的哪几种特征,从而提高男性魅力,实现科学脱单。当然这可能不符合工程伦理,同时创建这样一个数据集有着诸多困难)那么关于无监督学习:

非监督式学习是一种机器学习的方式,并不需要人力来输入标签。 它是监督式学习和强化学习等策略之外的一种选择。 在监督式学习中,典型的任务是分类和回归分析,且需要使用到人工预先准备好的范例(base)。 ... 无监督学习主要是针对(有)监督学习和强化学习而言的,可以通过对输入的解释将强化学习、监督学习和无监督学习区分开来。

这个是百科上的定义,那么实际举个例子就是这样。 在这里插入图片描述 现在这个上面有一堆点,现在我命令你去对它进行分类,怎么分。我现在要求对它分三类,对着一堆点分三类,现在这个是一个平面上的点,只有两个维度 也就是 x y 。那么这个就是最简单的一个实例,还有一个复杂一点的 lnstacart市场篮子分析 这个是一个机器学习的题目,让你对用户行为进行分类,筛选出用户比较喜欢聚集的位置。这个其实也是一个分类问题嘛,对地域分类,也刚好可以把地域进行平面处理,当然具体的操作要复杂一点,后面我们就来用这个来举个例子。

原理解析

那么在具体的算法过程中我们可以来设想一下。

在这里插入图片描述 这张图片,我们就假设我们要分三个类。我们应该怎么做。

选择中心点

首先我们必然是要选择三个中心点的,由于我们是无监督学习,所以我们根本不知道我们分类后的结果,自然我们不知道一开始的中心点是什么,所以最简单也比较合理的方式,就是随机选择三个点,作为我们的中心点。

聚类划分

接下来中心点我们有了,那接下来干啥。毫无疑问,那自然就是根据距离来判断了,所谓一句话近朱者赤近墨者黑。看这个点离哪个中心点的距离最近,距离越近,那么这个点就和那个中心点是一个类别的。那么在距离吧划分上面又涉及到几个方式了,一个是最典型的 欧氏距离 也就是 连点距离。 在这里插入图片描述 还有一个是曼哈顿距离 在这里插入图片描述

演示

下面一组图片可以非常生动地演示 在这里插入图片描述

纯数学叨逼叨

又到了我最烦琐的时刻了,我们对我们先前说的内容进行数学标准化。

算法流程

1)对于K-Means算法,首先要注意的是k值的选择,一般来说,我们会根据对数据的先验经验选择一个合适的k值,如果没有什么先验知识,则可以通过交叉验证选择一个合适的k值。

    2)在确定了k的个数后,我们需要选择k个初始化的质心,就像上图b中的随机质心。由于我?>们是启发式方法,k个初始化的质心的位置选择对最后的聚类结果和运行时间都有很大的影响,因此需>要选择合适的k个质心,最好这些质心不能太近。

    好了,现在我们来总结下传统的K-Means算法流程。 

    输入是样本集D={x1,x2,...xm},聚类的簇树k,最大迭代次数N

    输出是簇划分C={C1,C2,...Ck} 

    1) 从数据集D中随机选择k个样本作为初始的k个质心向量: {μ1,μ2,...,μk}     2)对于n=1,2,...,N

      a) 将簇划分C初始化为Ct=∅t=1,2...k       b) 对于i=1,2...m,计算样本xi和各个质心向量μj(j=1,2,...k)的距离:dij=||xi−μj||22,将xi标记最小的为dij所对应的类别λi。此时更新Cλi=Cλi∪{xi}       c) 对于j=1,2,...,k,对Cj中所有的样本点重新计算新的质心μj=1|Cj|∑x∈Cjx       e) 如果所有的k个质心向量都没有发生变化,则转到步骤3)

    3) 输出簇划分C={C1,C2,...Ck}

优缺点

    K-Means的主要优点有:

    1)原理比较简单,实现也是很容易,收敛速度快。

    2)聚类效果较优。

    3)算法的可解释度比较强。

    4)主要需要调参的参数仅仅是簇数k。

    K-Means的主要缺点有:

    1)K值的选取不好把握

    2)对于不是凸的数据集比较难收敛

    3)如果各隐含类别的数据不平衡,比如各隐含类别的数据量严重失衡,或者各隐含类别的方差不同,则聚类效果不佳。

    4) 采用迭代方法,得到的结果只是局部最优。

    5) 对噪音和异常点比较的敏感。

案例(lnstacart市场篮子分析)

这部分的话我就直接用 sklearn去做了,算法原理很简单,自己实现起来基本上没啥难度。 API:

from sklearn.cluster import KMeans

评估:

from sklearn.metrics import silhouette_score

探究用户对物品类别的喜好细分的,在这里的话就是通过聚类分析得到用户喜欢的物品的分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U38sJMcI-1637077656140)(C:\Users\31395\AppData\Roaming\Typora\typora-user-images\image-20211116233645003.png)]

这个早就有人做出来了

数据集:

链接:pan.baidu.com/s/1P9xwvyYA… 提取码:6666

import pandas as pd
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
#1.获取数据
order_products=pd.read_csv("./data/order_products__prior.csv")
products=pd.read_csv("./data/products.csv")
orders=pd.read_csv("./data/orders.csv")
aisles=pd.read_csv("./data/aisles.csv")
# 2、合并表
#合并aisles和products   aisle和product_id
tab1=pd.merge(aisles,products,on=["aisle_id","aisle_id"])[:100]
tab2=pd.merge(tab1,order_products,on=["product_id","product_id"])[:100]
tab3=pd.merge(tab2,orders,on=["order_id","order_id"])[:100]
#3.找到user_id和aisle之间的关系
table=pd.crosstab(tab3["user_id"],tab3["aisle"])
data=table[:10000]#取一部分节省时间
#4.PCA降维
#4.1实例化转换器类
transfer=PCA(n_components=0.95)
#4.2调用fit_transform
data_new=transfer.fit_transform(data)

#5.预估器流程
estimator=KMeans(n_clusters=3)
estimator.fit(data_new)
y_predict=estimator.predict(data_new)
#模型评估-轮廓系数
silhouette_num=silhouette_score(data_new,y_predict)
print("轮廓系数:\n",silhouette_num)