n_clusters:生成的聚类数,即产生的质心(centroids)数。默认为8
init:指定初始化方法。有三个可选值:’k-means++’, ‘random’,或者传递一个 ndarray 向量。默认值为 ‘k-means++’。
k-means++:用一种特殊的方法选定初始质心从而能加速迭代过程的收敛
random:随机从训练数据中选取初始质心。
如果传递的是一个ndarray,则应该形如 (n_clusters, n_features) 并给出初始质心。
n_init:用不同的质心初始化值运行算法的次数,最终解是在inertia意义下选出的最优结果。默认为10。
max_iter:执行一次k-means算法所进行的最大迭代数。默认为300。
tol:与inertia结合来确定收敛条件。默认为1e-4 。
precompute_distances:预计算距离,计算速度更快但占用更多内存。三个可选值,‘auto’,True 或者 False。默认为auto。
auto:如果样本数乘以聚类数大于 12million 的话则不预计算距离。这相当于使用双倍精度的每个作业大约100mb的开销
True:总是预先计算距离。
False:永远不预先计算距离。
random_state:用于初始化质心的生成器(generator)。如果值为一个整数,则确定一个seed。此参数默认值为numpy的随机数生成器。
copy_x:默认值=True。当我们precomputing distances时,将数据中心化会得到更准确的结果。如果把此参数值设为True,则原始数据不会被改变。如果是False,则会直接在原始数据上做修改并在函数返回值时将其还原。但是在计算过程中由于有对数据均值的加减运算,所以数据返回后,原始数据和计算前可能会有细小差别。
n_jobs:指定计算所用的进程数,内部原理是同时进行n_init指定次数的计算。
若值为 -1,则用所有的CPU进行运算。若值为1,则不进行并行运算,这样的话方便调试。
若值小于-1,则用到的CPU数为(n_cpus + 1 + n_jobs)。因此如果 n_jobs值为-2,则用到的CPU数为总CPU数减1。
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) # X是数据特征值集合,y是类别 fig, ax1 = plt.subplots(1) # 创建一个子图,返回 Figure对象(fig) 和 子图对象(ax1)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()
接下来使用Kmeans进行聚类
from sklearn.cluster import KMeans k = 3 # 猜测的 簇 个数cluster0 = KMeans(n_clusters=k, random_state=0).fit(X) # 创建模型并fit,先 猜测 数据中有 三簇# 属性 labels_:模型 聚类 得到的类别(每个样本所对应类)y_pred = cluster0.labels_ print("使用模型进行聚类得到的类别: \n", y_pred)# 属性 cluster_centers_:最终得到的所有的质心centroid = cluster0.cluster_centers_print("最终的质心: \n", centroid)print(centroid.shape)# 属性 inertia_:总距离平方和---越小越好inertia = cluster0.inertia_print("总距离平方和: ", inertia)
运行结果:
下面,画图(结果可视化)。color = ["red","pink","orange","gray"]fig, ax1 = plt.subplots(1)for i in range(k): 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=30, c="black") # 画出质心plt.show()
结果:
可以看到,当 k=3 时,总距离平方和为1903,现在把 k 设为 4 ,看一下总距离平方和会不会降低一点。
k = 4cluster1 = KMeans(n_clusters=k, random_state=0).fit(X)# 属性 inertia_:总距离平方和---越小越好inertia = cluster1.inertia_print("总距离平方和: ", inertia)
当 k=4 时,总距离平方和大大降低了。那 k=5 又会怎样呢?
我们把上述代码的k=4改为k=5,运行:
可以看到,总距离平方和又再次降低了。实际上,当我们设的 k 越大(不超过样本数),总距离平方和就会越小。这是因为,k越大,则质心就越多,例如当k为500时,那么就相当于每一个数据点都是一个质心,那此时总距离平方和直接就会等于0了。那如何才能衡量模型的好坏呢(评估模型)?
因为KMeans的目标是确保“簇内差异小,簇外差异大”,所以就可以通过衡量簇内差异来衡量聚类的效果。总距离平方和是用距离来衡量簇内差异的指标,但通过上面的实验,可以看到,他并不能作为衡量的标准。这里可以使用 轮廓系数 来衡量。
轮廓系数范围是(-1,1),其中:
轮廓系数 越接近 1 表示 样本 与 自己所在的簇中的样本 很相似,并且与 其他簇 中的样本 不相似
轮廓系数就为 负 时,代表 样本点 与 簇外的样本 更相似
轮廓系数为 0 时,代表 两个簇 中的 样本相似度 一致,两个簇本应该是一个簇。
如果一个簇中的大多数样本具有比较高的轮廓系数,则簇会有较高的总轮廓系数,则整个数据集的平均轮廓系数越高,则聚类是合适的。
如果许多样本点具有低轮廓系数甚至负值,则聚类是不合适的,聚类的超参数K可能设定得 太大 或 太小。
在sklearn中,可以使用模块 metrics 中的类 silhouette_score 来计算轮廓系数,它返回的是一个数据集中,所有样本的轮廓系数的均值。
还有同在 metrics 模块中的 silhouette_sample,它的参数与轮廓系数一致,但返回的是数据集中每个样本自己的轮廓系数。
from sklearn.metrics import silhouette_scorefrom sklearn.metrics import silhouette_samples score0 = silhouette_score(X, cluster0.labels_) # 使用k=3时,数据集 得到的聚类效果(轮廓系数)score1 = silhouette_score(X, cluster1.labels_) # k=4score2 = silhouette_score(X, cluster2.labels_) # k=5print(score0)print(score1)print(score2)
可以看到,k=4时,轮廓系数最大,也就是聚类效果最好。我们也可以查看 数据集上 每个数据 的 轮廓系数(这里以k=4的聚类结果为例)。
print(silhouette_samples(X,cluster1.labels_))
可以看到,轮廓系数基本都为正,这代表聚类效果不错。
3、调参
这里将介绍
基于轮廓系数来选择 KMeans 函数中的 n_clusters,也就是簇的个数 K。我们通常会 绘制
轮廓系数分布图 和
聚类后的数据分布图 来选择我们的最佳n_clusters。
from sklearn.cluster import KMeansfrom sklearn.metrics import silhouette_samples, silhouette_scoreimport matplotlib.pyplot as pltimport matplotlib.cm as cmimport numpy as np# 下面两行用于使用 matplotlib 画图时 显示中文字体plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签plt.rcParams['axes.unicode_minus']=False #用来正常显示负号for k in [2,3,4,5,6,7]: n_clusters = k 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("当n_clusters为 ", n_clusters, " 时,所有样本点的轮廓系数是 ", silhouette_avg) sample_silhouette_values = silhouette_samples(X, cluster_labels) # 获得每个样本点的轮廓系数 y_lower = 10 # 设置 y轴 的初始取值 # 对每个簇进行循环 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_upper = y_lower + size_cluster_i # 一个簇在y轴的取值由初始值(y_lower)开始,到初始值加上这个簇中的样本数量结束(y_upper) color = cm.nipy_spectral(float(i)/n_clusters) #用i的浮点数除以n_clusters,在不同的i下生成不同的小数,以确保所有的簇都有不同的颜色 # fill_between:让一个范围的柱状图都统一颜色的函数 # 其 范围是在 纵坐标 上,参数输入为:纵坐标的下限,纵坐标的上限,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("不同簇下的轮廓系数") # 图的名字 ax1.set_xlabel("轮廓系数值") # x轴标签 ax1.set_ylabel("簇标签") # y轴标签 ax1.axvline(x=silhouette_avg, color="red", linestyle="--") # 把整个数据集上的 轮廓系数的均值 以 虚线 形式放入图中 ax1.set_yticks([]) # 让y轴不显示任何刻度 ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1]) # 让X轴上的刻度显示为规定的列表 # 第二个子图 # 首先获取新的颜色,由于没有循环需要一次性生成多个小数来获取多个颜色 # 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("聚类后的数据分布图") ax2.set_xlabel("特征值1") ax2.set_ylabel("特征值2") # 为整个图设置标题 plt.suptitle(("Silhouette analysis for KMeans clustering on sample data with n_clusters = %d" % n_clusters), fontsize=14, fontweight='bold') plt.show()
运行结果比较长,这里截取部分。
通过对不同k值下的轮廓系数进行比较,会发现当 k=4 时,该数据集的聚类效果最好。其中柱状图中的三个颜色分别对应了其相应颜色的簇中的轮廓系数。