Kmeans
簇:Kmeans
算法将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上看来簇是一个又一个聚集一起的数据,在一个簇中的数据就认为是同一类,簇就是聚类的结果表现
质心:簇中所有数据的均值u通常被称为这个簇的"质心"
质心的个数与聚类后的类别数一致
在Kmeans
算法中,簇的个数k是一个超参数,需要人为输入来确定。Kmeans
的核心任务就是根据我们设好的k,找出k个最优的质心,并将离这些质心最近的数据分别分配到这些质心代表的簇中去,具体过程如下:
当我们找到一个质心,在每次迭代中被分配到这个质心上的样本都是一致的,即每次新生成的簇都是一致的,所有的样本点都不会再从一个簇转移到另一个簇,质心就不会变化了
如图所示【将数据分成4簇,白色x代表质心】
被分在同一个簇中的数据是有相似性的,而不同簇中的数据是不同的,当聚类完毕之后,就要分别去研究每个簇中的样本都有什么性质,根据业务需求制定不同的策略
聚类算法追求"簇内差异小,簇外差异大"【差异:由样本点到其所在簇的质心的距离来衡量】
对于一个簇,所有样本点到质心的距离之和越小,就认为这个簇中的样本越相似,簇内差异就越小。样本点到质心的距离可由距离来衡量:
簇内平方和
整体平方和
Total Cluster Sum of Square
),又叫做total inertia
。Total Inertia
越小,代表每个簇内样本越相似,聚类效果就越好Kmeans
有损失函数吗?有,Kmeans
追求的是,求解能够让簇内平方和最小化的质心。在质心不断变化不断迭代的过程中,整体平方和是越来越小的,当整体平方和最小的时候,质心就不再发生变化了,即求解问题,变成了最优化问题
Kmeans
中,在一个固定的簇数k下,最小化整体平方和来求解最佳质心,并基于质心的存在去进行聚类,并且,整体距离平方和的最小值可以使用梯度下降来求解,因此有人认为:簇内平方和或整体平方和是Kmeans
的损失函数没有
Kmeans
不求解参数,它的本质也不是在拟合数据,而是对数据进行一种探索。所以有些人认为:Kmeans
不存在损失函数,整体平方和更像是Kmeans
的模型评估指标,而非损失函数kmeans
对结果的预测Kmeans
算法通常不需要预测结果,因为该算法本质上是在对未知分类数据的探索,但是在某些情况下我们可以使用predict进行预测操作predict
方法。如果数据量还行,直接使用fit
后调用labels_
查看聚类结果class sklearn.cluster.KMeans(n_clusters=8,init='k-means++',n_init=10,max_iter=300,tol=0.0001,precompute_distances='auto',verbase=0,random_state=None,copy_x=True,n_jobs=None,algorthm='auto')
n_clusters
:是KMeans
中的k,表示模型要分几类,必填参数,默认为8类,通常的聚类结果会是一个小于8的结果,在聚类之前,不知道n_clusters
是多少,即要对它进行探索random_state
:初始化质心的生成器labels_
:查看聚好的类别,每个样本所对应的类cluster_centers_
:查看质心坐标intertia_
:查看总距离平方和Kmeans
探索拿到一个数据集,我们希望能够通过绘图先观察一下这个数据集的数据分布,以此来为我们聚类时输入的n_clusters做一个参考,自己创建一个数据集make_blobs
,自己创建的,有标签
from sklearn.datasets import make_blobs import matplotlib.pyplot as plt #自己创建数据集,特征维度为2,质心为4,分4类,500个样本 X,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1) color=['red','pink','orange','gray'] fig,ax1=plt.subplots(1) for i in range(4): ax1.scatter( X[y==i,0], X[y==i,1], marker='o',#点的形状 s=8,#点的大小 c=color[i] #颜色 ) plt.show()
基于这个分布,使用kmeans
,假设数据有3簇
#假设为3簇 from sklearn.cluster import KMeans from sklearn.datasets import make_blobs #自己创建数据集,特征维度为2,质心为4,分4类,500个样本 X,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1) n_clusters = 3 cluster = KMeans(n_clusters=n_clusters,random_state=0).fit(X) y_pred=cluster.labels_ #重要属性,查看聚好的类别,每个样本所对应的类 centroid=cluster.cluster_centers_ #重要属性查看质心 # array([[-8.0807047 , -3.50729701], # [-1.54234022, 4.43517599], # [-7.11207261, -8.09458846]]) inertia=cluster.inertia_ #重要属性,查看总距离平方和 # 1903.4503741659223
画图,显示质心
from sklearn.cluster import KMeans from sklearn.datasets import make_blobs #自己创建数据集,特征维度为2,质心为4,分4类,500个样本 X,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1) n_clusters = 3 cluster = KMeans(n_clusters=n_clusters,random_state=0).fit(X) centroid=cluster.cluster_centers_ #重要属性查看质心 color=['red','pink','orange','gray'] fig,ax1=plt.subplots(1) for i in range(n_clusters): ax1.scatter(X[y_pred==i,0],X[y_pred==i,1],marker='o',s=8,c=color[i]) ax1.scatter(centroid[:,0],centroid[:,1],marker='x',s=15,c='black') plt.show()
使用部分数据
from sklearn.cluster import KMeans from sklearn.datasets import make_blobs X,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1) n_clusters=3 cluster=KMeans(n_clusters=n_clusters,random_state=0).fit(X) y_pred=cluster.labels_ #重要属性,查看聚好的类别,每个样本所对应的类 cluster_smallsub=KMeans(n_clusters=n_clusters,random_state=0).fit(X[:200]) #使用模型对X进行分类预测 y_pred_ = cluster_smallsub.predict(X) (y_pred==y_pred_).sum()
【面试题】如何衡量聚类算法的效果?
簇内平方和(inertia
)的缺点
首先,它不是有界的,只知道inertia
越小越好,是0最好。但是我们不知道,一个较小的inertia
有没有达到模型的极限,能否继续提高
计算太容易受到特征的数目的影响,数据维度很大时,interia
的计算量会爆炸,不适合用来一次次评估模型
会受到超参数k的影响,随着k越大,interia
会越来越小,但不代表模型的效果越来越好
使用inertia
作为指标,会让聚类算法在一些细长簇,环形簇,或者不规则形状的聚类时,效果不佳:
轮廓系数【轮廓系数是最常用的聚类算法的评价指标】
在99%的情况下,是对没有真实标签的数据进行探索,即对不知道真正答案的数据进行聚类。这种聚类,是完全依赖于评价簇内的稠密程度(簇内差异小)和簇间的离散程度(簇外差异大)来评估评估聚类的效果,轮廓系数是最常用的聚类算法的评价指标。它是对每个样本来定义的,能同时衡量:
单个轮廓系数计算为:
轮廓系数范围是(-1,1):
如果一个簇中的大多数样本具有较高的轮廓系数,则簇会有较高的总轮廓系数,则整个数据集的平均轮廓系数越高,即聚类是合适的
如果许多样本点具有低轮廓系数甚至负数,则聚类不合适,聚类的超参数k可能设定的太大或太小
轮廓系数的计算
silhouette_score
from sklearn.metrics import silbouette_score
,返回一个数据集中所有样本的轮廓系数的均值silhouette_sample
from sklearn.metrics import silhouetet_samples
,返回数据集中每个样本自己的轮廓系数from sklearn.cluster import KMeans from sklearn.datasets import make_blobs from sklearn.metrics import silhouette_score from sklearn.metrics import silhouette_samples X,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1) n_clusters=3 cluster=KMeans(n_clusters=n_clusters,random_state=0).fit(X) y_pred=cluster.labels_ silhouette_score(X,y_pred) #0.5882004012129721 silhouette_samples(X,y_pred)