1、聚类算法又叫做“无监督分类”,其目的是将数据划分成有意义或有用的组(或簇)。这种划分可以基于我们的业务需求或建模需求来完成,也可以单纯地帮助我们探索数据的自然结构和分布。
2、KMeans算法将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上来看是簇是一组一组聚集在一起的数据,在一个簇中的数据就认为是同一类。簇就是聚类的结果表现。簇中所有数据的均值通常被称为这个簇的“质心”(centroids)。在一个二维平面中,一簇数据点的质心的横坐标就是这一簇数据点的横坐标的均值,质心的纵坐标就是这一簇数据点的纵坐标的均值。同理可推广至高维空间。
3、KMeans追求的是‘簇内差异小,簇间差异大’。
所有簇的簇内平方和相加,就得到了整体平方和,又叫做total inertia。Total Inertia越小,代表着每个簇内样本越相似,聚类的效果就越好。因此KMeans追求的是,求解能够让Inertia最小化的质心。实际上,在质心不断变化不断迭代的过程中,总体平方和是越来越小的。
注:损失函数本质是用来衡量模型的拟合效果的,只有有着求解参数需求的算法,才会有损失函数。Kmeans不求解什么参数,它的模型本质也没有在拟合数据,而是在对数据进行一种探索,故Kmeans不存在损失函数,Inertia更像是Kmeans的评估指标,而不是损失函数。
除了模型本身的效果之外,我们还使用另一种角度来度量算法:算法复杂度。算法的复杂度分为时间复杂度和空间复杂度,时间复杂度是指执行算法所需要的计算工作量,常用大O符号表述;而空间复杂度是指执行这个算法所需要的内存空间。如果一个算法的效果很好,但需要的时间复杂度和空间复杂度都很大,那我们将会权衡算法的效果
和所需的计算成本。和KNN一样,KMeans算法是一个计算成本很大的算法。
聚类模型的结果不是某种标签输出,并且聚类的结果是不确定的,其优劣由业务需求或者算法需求来决定,并且没有永远的正确答案。
用inertia作为衡量指标并不合适,一个较小的Inertia究竟有没有达到模型的极限,能否继续提高;Inertia的计算太容易受到特征数目的影响,数据维度很大的时候,Inertia的计算量会陷入维度诅咒之中,计算量会爆炸,不适合用来一次次评估模型;Inertia还会受到超参数K的影响,随着K越大,Inertia注定会越来越小,但这并不代表模型的效果越来越好了;Inertia对数据的分布有假设,它假设数据满足凸分布并且它假设数据是各向同性的,即是说数据的属性在不同方向上代表着相同的含义,但是现实中的数据往往不是这样,所以使用Inertia作为评估指标,会让聚类算法在一些细长簇,环形簇,或者不规则形状的流形时表现不佳。
4、KMeans模型评估指标,分两种:
标签已知时,如果拥有真实标签,我们更倾向于使用分类算法。但不排除我们依然可能使用聚类算法的可能性。如果我们有样本真实聚类情况的数据,我们可以对于聚类算法的结果和真实结果来衡量聚类的效果。常用的有以下三种方法:
互信息分;V-measure(基于条件上分析的一系列直观度量);调整兰德系数
真实标签未知时,轮廓系数(评价簇内的稠密程度(簇内差异小)和簇间的离散程度(簇外差异大)来评估聚类的效果),卡林斯基-哈拉巴斯指数(Calinski-Harabaz Index,简称CHI,也被称为方差比标准),戴维斯-布尔丁指数(Davies-Bouldin)以及权变矩阵(Contingency Matrix)
轮廓系数的范围是(-1,1),值越接近1表示样本与自己所在的簇中的样本很相似,并且与其他簇中的样本不相似;当样本点与簇外的样本更相似的时候,轮廓系数就为负;当轮廓系数为0时,则代表两个簇中的样本相似度一致,两个簇本应该是一个簇。在sklearn中,我们使用模块metrics中的类silhouette_score来计算轮廓系数,它返回的是一个数据集中,所有样本的轮廓系数的均值。但我们还有同在metrics模块中的silhouette_sample,它的参数与轮廓系数一致,但返回的是数据集中每个样本自己的轮廓系数。
基于轮廓系数选择最佳的n_clusters
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
#创建数据集
X,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1)
fig,ax1=plt.subplots(1)
ax1.scatter(X[:,0],X[:,1],marker='o',s=8)
plt.show()
#添加颜色
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()
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples,silhouette_score
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
#基于轮廓系数来选择最佳的n_clusters
#知道每个聚出来的类的轮廓系数是多少,还有各个类之间的轮廓系数的对比
#知道聚类完毕以后图像的分布是什么样的
#先设定要分成的簇数
n_clusters=4
#创建一个画布,画布上有一行两列两个图
fig,(ax1,ax2)=plt.subplots(1,2)
#设置画布尺寸
fig.set_size_inches(18,7)
ax1.set_xlim([-0.1,1])
ax1.set_ylim([0,X.shape[0]+(n_clusters+1)*10])
#建模,调用聚类好的标签
clusterer=KMeans(n_clusters=n_clusters,random_state=10).fit(X)
cluster_labels=clusterer.labels_
#调用轮廓系数分数,silhouette_avg生成所有样本点轮廓系数的均值
#需要输入两个参数,特征矩阵X与聚类完毕的标签
silhouette_avg = silhouette_score(X, cluster_labels)
#打印现有簇数量下,轮廓系数是多少
print("For n_clusters =", n_clusters,
"The average silhouette_score is :", silhouette_avg)
#调用silhouette_samples,返回每个样本点的轮廓系数,就是横坐标
sample_silhouette_values = silhouette_samples(X, cluster_labels)
#设置Y轴的初始取值
y_lower = 10
#对每个簇进行循环
for i in range(n_clusters):
#从每个样本的轮廓系数结果中抽取第i个簇的轮廓系数,并进行排序
ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i]
#注意,.sort会直接改掉原数据的顺序
ith_cluster_silhouette_values.sort()
#查看簇中究竟有多少个样本
size_cluster_i = ith_cluster_silhouette_values.shape[0]
#一个簇在y州的取值是由初始值(y_lower)开始,到初始值加上这个簇中的样本数量结束(y_upper)
y_upper = y_lower + size_cluster_i
#用i的浮点数除以n_clusters,在不同的i下生成不同的小数,以确保所有的簇都有不同的颜色
color = cm.nipy_spectral(float(i)/n_clusters)
#fill_between是让一个范围的柱状图都统一颜色的函数,
#fill_betweenx的范围是在纵坐标上,参数输入(纵坐标的下限,纵坐标的上限,X轴上的取值,柱状图的颜色)
ax1.fill_betweenx(np.arange(y_lower, y_upper)
,ith_cluster_silhouette_values
,facecolor=color
,alpha=0.7)
#为每个簇的轮廓系数写上编号,并让簇的编号显示在坐标轴每个条形图的中间位置
#text参数(要显示编号位置的横坐标,纵坐标,编号内容)
ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
#为下一个簇计算新的y轴上的初始值,每一次迭代后y再加上10以保证不同簇的图像之间显示有空隙
y_lower = y_upper + 10
ax1.set_title("The silhouette plot for the various clusters.")
ax1.set_xlabel("The silhouette coefficient values")
ax1.set_ylabel("Cluster label")
# 把整个数据集上的轮廓系数的均值以虚线形式放入图中
ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
#让y轴不显示任何刻度
ax1.set_yticks([])
#让X轴上的刻度显示为规定的列表
ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
#开始处理第二个图,首先获取新的颜色,由于没有循环需要一次性生成多个小数来获取多个颜色
#cluster_labels.astype(float) 生成浮点数,nipy_spectral只能用浮点数,500个值只有4个颜色
colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
ax2.scatter(X[:, 0], X[:, 1],marker='o',s=8,c=colors)
#把生成的质心放在图像中
centers = clusterer.cluster_centers_
ax2.scatter(centers[:, 0], centers[:, 1], marker='x',c="red", alpha=1, s=200)
ax2.set_title("The visualization of the clustered data.")
ax2.set_xlabel("Feature space for the 1st feature")
ax2.set_ylabel("Feature space for the 2nd feature")
#为整个图设置标题
plt.suptitle(("Silhouette analysis for KMeans clustering on sample data "
"with n_clusters = %d" % n_clusters),
fontsize=14, fontweight='bold')
plt.show()无锡妇科医院 http://www.bhnnk120.com/
#将上述过程包装称循环
for n_clusters in [2,3,4,5,6,7]:
n_clusters = n_clusters
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.set_size_inches(18, 7)
ax1.set_xlim([-0.1, 1])
ax1.set_ylim([0, X.shape[0] + (n_clusters + 1) * 10])
clusterer = KMeans(n_clusters=n_clusters, random_state=10).fit(X)
cluster_labels = clusterer.labels_
silhouette_avg = silhouette_score(X, cluster_labels)
print("For n_clusters =", n_clusters,"The average silhouette_score is :", silhouette_avg)
sample_silhouette_values = silhouette_samples(X, cluster_labels)
y_lower = 10
for i in range(n_clusters):
ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i]
ith_cluster_silhouette_values.sort()
size_cluster_i = ith_cluster_silhouette_values.shape[0]
y_upper = y_lower + size_cluster_i
color = cm.nipy_spectral(float(i)/n_clusters)
ax1.fill_betweenx(np.arange(y_lower, y_upper)
,ith_cluster_silhouette_values
,facecolor=color
,alpha=0.7)
ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
y_lower = y_upper + 10
ax1.set_title("The silhouette plot for the various clusters.")
ax1.set_xlabel("The silhouette coefficient values")
ax1.set_ylabel("Cluster label")
ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
ax1.set_yticks([])
ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
ax2.scatter(X[:, 0], X[:, 1],marker='o',s=8,c=colors)
centers = clusterer.cluster_centers_
# Draw white circles at cluster centers
ax2.scatter(centers[:, 0], centers[:, 1], marker='x',c="red", alpha=1, s=200)
ax2.set_title("The visualization of the clustered data.")
ax2.set_xlabel("Feature space for the 1st feature")
ax2.set_ylabel("Feature space for the 2nd feature")
plt.suptitle(("Silhouette analysis for KMeans clustering"
"with n_clusters = %d" % n_clusters),fontsize=14, fontweight='bold')
plt.show()
5、初始质心(init)
init:可输入**“k-means++”,“random"或者一个n维数组**。这是初始化质心的方法,默认"k-means++"。
输入"kmeans++”:一种为K均值聚类选择初始聚类中心的聪明的办法(使得初始质心通常彼此远离),以加速收敛。
"random"下,如果不指定随机数种子,则sklearn中的K-means并不会只选择一个随机模式扔出结果,而会在每个随机数种子下运行多次,并使用结果最好的一个随机数种子来作为初始质心。可以使用参数n_init来选择每个随机数种子下运行的次数,这个参数不常用到,默认10次,如果我们希望运行的结果更加精确,那我们可以增加这个参数n_init的值来增加每个随机数种子下运行的次数。然而这种方法依然是基于随机性的。
如果输入了n维数组,数组的形状应该是(n_clusters,n_features)并给出初始质心。
6、max_iter & tol:让迭代停下来
当质心不再移动,Kmeans算法就会停下来,但在完全收敛之前,可以使用max_iter(最大迭代次数)或者tol(两次迭代间Inertia下降的量),这两个参数来让迭代提前停下来。数据量特别大时可以使用。
max_iter:整数,默认300,单次运行的k-means算法的最大迭代次数
tol:浮点数,默认1e-4,两次迭代间Inertia下降的量,如果两次迭代之间Inertia下降的值小于tol所设定的值,迭代就会停下