sklearn.cluster.KMeans
-
class sklearn.cluster.KMeans (n_clusters=8, init=’k-means++’, n_init=10, max_iter=300, tol=0.0001,precompute_distances=’auto’, verbose=0, random_state=None, copy_x=True, n_jobs=None, algorithm=’auto’)
-
n_clusters是KMeans中的k,表示着要分几类。这是KMeans当中唯一一个必填的参数,默认为8类,但通常聚类结果会是一个小于8的结果。通常,在开始聚类之前,并不知道n_clusters究竟是多少,因此要对它进行探索
-
当拿到一个数据集,如果可能的话,能够通过绘图先观察一下这个数据集的数据分布,以此来为聚类时输入的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)
# x是特征矩阵,x.shape=(500,2) y为标签(500,)
fig,ax1 = plt.subplots(1) # 生成一个子图 fig画布
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] # bool索引
,marker='o'
,c=color[i]
)
plt.show()
一、假定不知道上述数据的分布做聚类
from sklearn.cluster import KMeans
n_clusters = 3
cluster = KMeans(n_clusters=n_clusters,random_state=0).fit(x)
1.1、重要属性
- .labels_:查看聚好的类别,每个样本所对应的类
- KMeans因为不需要建立模型或者预测结果,因此只需要fit就能够得到聚类的结果
- KMeans也有接口predict和fit_predict,表示学习数据x并对x的类别进行预测
- 但所得到的结果和不调用predict,直接fit后用属性labels一样
- .cluster_centers_:查看质心
- .inertia_:查看总距离平方和
y_pred = cluster.labels_
y_pred
# 假设数据样本非常大,用前面一部分数据来做训练计算出质心,后面的用predict()来预测
cluster_samllsub = KMeans(n_clusters=n_clusters,random_state=0).fit(x[:200])
y_pred_ = cluster_samllsub.predict(x)
y_pred_
# 查看用少量数据计算质心与用全部数据计算质心的区别
y_pred == y_pred_
centroid = cluster.cluster_centers_
centroid # 查看质心
inertia = cluster.inertia_
inertia # 查看总距离平方和
- inertia:(整体平方和)越小代表分簇的效果越好,但是n_clusters越大,inertia必定会越小
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()
# 对比上面的n_clusters=3要好
n_clusters =4
cluster_ = KMeans(n_clusters=n_clusters,random_state=0).fit(x)
inertia_ = cluster_.inertia_
inertia_
n_clusters =5
cluster_ = KMeans(n_clusters=n_clusters,random_state=0).fit(x)
inertia_ = cluster_.inertia_
inertia_
n_clusters =6
cluster_ = KMeans(n_clusters=n_clusters,random_state=0).fit(x)
inertia_ = cluster_.inertia_
inertia_
1.2、聚类算法模型评估指标
1.2.1、当真实标签已知时
- 如果拥有真实标签,更倾向于使用分类算法。
- 但依然可能使用聚类算法。如果有样本真实聚类情况的数据,可以对于聚类算法的结果和真实结果来衡量聚类的效果。常用的有以下三种方法:
1.2.2、当真实标签未知时:轮廓系数
-
在99%的情况下,是对没有真实标签的数据进行探索,也就是对不知道真正答案的数据进行聚类。
-
这样的聚类,是完全依赖于评价簇内的稠密程度(簇内差异小)和簇间的离散程度(簇外差异大)来评估聚类的效果。
-
其中轮廓系数是最常用的聚类算法的评价指标。它是对每个样本来定义的,它能够同时衡量:
- 1)样本与其自身所在的簇中的其他样本的相似度a,等于样本与同一簇中所有其他点之间的平均距离
- 2)样本与其他簇中的样本的相似度b,等于样本与下一个最近的簇中的所有点之间的平均距离
-
根据聚类的要求”簇内差异小,簇外差异大“,我们希望b永远大于a,并且大得越多越好。
单个样本的轮廓系数计算为:
-
轮廓系数范围是(-1,1),其中值越接近1表示样本与自己所在的簇中的样本很相似,并且与其他簇中的样本不相似,当样本点与簇外的样本更相似的时候,轮廓系数就为负。
-
当轮廓系数为0时,则代表两个簇中的样本相似度一致,两个簇本应该是一个簇。
-
可以总结为轮廓系数越接近于1越好,负数则表示聚类效果非常差
-
如果一个簇中的大多数样本具有比较高的轮廓系数,则簇会有较高的总轮廓系数,则整个数据集的平均轮廓系数越高,则聚类是合适的。
-
如果许多样本点具有低轮廓系数甚至负值,则聚类是不合适的,聚类的超参数K可能设定得太大或者太小
-
使用模块metrics中的类silhouette_score来计算轮廓系数,它返回的是一个数据集中,所有样本的轮廓系数的均值。
-
同在metrics模块中的silhouette_samples,它的参数与轮廓系数一致,但返回的是数据集中每个样本自己的轮廓系数
from sklearn.metrics import silhouette_score
from sklearn.metrics import silhouette_samples
# 分三簇时
silhouette_score(x,y_pred) # 数据 预测标签
# 分四簇时
silhouette_score(x,cluster_.labels_)
# 分5簇时
silhouette_score(x,cluster_.labels_)
# 每一个样本所对应的轮廓系数
silhouette_samples(x,y_pred)
1.2.3、当真实标签未知时:Calinski-Harabaz Index (卡林斯基-哈拉巴斯指数:简称CHI,也被称为方差比标准)
- Calinski-Harabaz指数越高越好。对于有k个簇的聚类而言,Calinski-Harabaz指数s(k)写作如下公式:
- 其中N为数据集中的样本量,k为簇的个数(即类别的个数), B k B_k Bk是组间离散矩阵,即不同簇之间的协方差矩阵, W k W_k Wk是簇内离散矩阵,即一个簇内数据的协方差矩阵。
- 数据之间的离散程度越高,协方差矩阵的迹就会越大。组内离散程度低,协方差的迹就会越小
- 因此Calinski-harabaz指数越高越好
from sklearn.metrics import calinski_harabaz_score
calinski_harabaz_score(x,y_pred)
- calinski-Harabaz指数没有界,在凸型的数据上的聚类也会和轮廓系数一样表现虚高。
- 但是比起轮廓系数,它有一个巨大的优点,就是计算非常快速。
- 魔法命令%%timeit来计算一个命令的运算时间(至少7次),另一种方法:时间戳计算运行时间。
from time import time
t0 = time()
calinski_harabaz_score(x,y_pred)
print(time() - t0)
t1 = time()
silhouette_score(x,y_pred)
print(time()-t1)
# 时间戳通过datetime中的fromtimestamp转换成真正的时间
import datetime
datetime.datetime.fromtimestamp(t1).strftime("%Y-%M-%D %H:%M:%S")
二、案例:基于轮廓系数来选择n_clusters
- 通常会绘制轮廓系数分布图和聚类后的数据分布图来选择最佳的:n_clusters
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples,silhouette_score
import matplotlib.pyplot as plt
import matplotlib.cm as cm # colormap
import numpy as np
import pandas as pd
- 基于轮廓系数来选择最佳的:n-clusters
- 要知道每个聚出来的类的轮廓系数是多少,并且要一个各个类之间轮廓系数之间的对比
- 要知道聚类完之后的图像的分布样子
# 假定要分的簇的数量为4 对上述内容初步探索
n_clusters = 4
# 创建画布,画布为一行两列两个子图
fig,(ax1,ax2) = plt.subplots(1,2)
# 画布尺寸
fig.set_size_inches(18,7)
# 轮廓系数图像画横向条形图,横坐标为轮廓系数值,纵坐标为每个样本
# 轮廓系数取值在[-1,1],但希望轮廓系数至少大于0
# 设定x轴的取值为[-0.1,1]
ax1.set_xlim([-0.1,1])
# 纵坐标从0开始,最大值取到x.shape[0]
# 每个簇能够排列到一起,不同簇之间有一定的空隙
# 图像展示的为不同的条形图聚合成的块,对应一个簇
# 在设定纵坐标的取值范围时,在x.shape[0]上加一个距离,留作间隔使用
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_score生成的是所有样本点的轮廓系数均值
# 需要输入的参数为:特征矩阵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轴初始值,与x轴有一定距离
y_lower = 10
# 对每一个簇进行循环
for i in range(n_clusters):
# 从返回的每个样本点的轮廓系数中取出第i簇的轮廓系数,并对其进行排序
ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i] # bool索引
# .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
# colormap库中,使用小数来调用颜色的函数
# 在nipy_spectral([输入任意小数代表一个颜色])
# 让每个簇的颜色不同,保证每次生成的小数不同即可
color = cm.nipy_spectral(float(i)/n_clusters)
######################## 开始填充子图1中的内容 ###########################
# fill_between : 让一个范围中的柱状图都统一颜色的函数
# fill_betweenx : x方向填充,填充对象为选定的y
# fill_betweeny : y方向填充,填充对象为选定的x
# 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
# 给图1加上标题、横坐标轴、纵坐标轴的名字
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])
#################### 对第二个图进行处理 ##################################
# 获取新的颜色,一次生成多个小数来获取多个颜色
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
)
# 为图2设置标题
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()
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
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 on sample data "
"with n_clusters = %d" % n_clusters)
,fontsize=14
, fontweight='bold'
)
plt.show()
三、重要参数init & random_state & n_init:初始质心怎么放好?
-
放置初始质心。如果有足够的时间,K-means一定会收敛,但Inertia可能收敛到局部最小值。是否能够收敛到真正的最小值很大程度上取决于质心的初始化。- - init就是用来帮助决定初始化方式的参数。
-
可以使用random_state参数来控制每次生成的初始质心都在相同位置,甚至可以画学习曲线来确定最优的random_state是哪个整数。
-
可以使用参数n_init来选择,每个随机数种子下运行的次数。这个参数不常用到,默认10次,如果希望运行的结果更加精确,可以增加这个参数n_init的值来增加每个随机数种子下运行的次数。然而这种方法依然是基于随机性的
-
init:可输入"k-means++“,“random"或者一个n维数组。这是初始化质心的方法,默认"k-means++”。输入"kmeans++”:一种为K均值聚类选择初始聚类中心的聪明的办法,以加速收敛。如果输入了n维数组,数组的形状应该是(n_clusters,n_features)并给出初始质心。
-
random_state:控制每次质心随机初始化的随机数种子
-
n_init:整数,默认10,使用不同的质心随机初始化的种子来运行k-means算法的次数。最终结果会是基于Inertia来计算的n_init次连续运行后的最佳输出
plus = KMeans(n_clusters = 10).fit(x)
plus.n_iter_ # 返回迭代次数
random = KMeans(n_clusters = 10,init="random",random_state=13).fit(x)
random.n_iter_
四、重要参数max_iter & tol:让迭代停下来
- 当质心不再移动,Kmeans算法就会停下来。
- 在完全收敛之前,可以使用max_iter,最大迭代次数,或者tol,两次迭代间Inertia下降的量,这两个参数来让迭代提前停下来。
- max_iter:整数,默认300,单次运行的k-means算法的最大迭代次数
- tol:浮点数,默认1e-4,两次迭代间Inertia下降的量,如果两次迭代之间Inertia下降的值小于tol所设定的值,迭代就会停下
random = KMeans(n_clusters = 10,init="random",max_iter=3,random_state=25).fit(x)
y_pred_max10 = random.labels_
silhouette_score(x,y_pred_max10)
random = KMeans(n_clusters = 10,init="random",max_iter=10,random_state=20).fit(x)
y_pred_max20 = random.labels_
silhouette_score(x,y_pred_max20)
五、函数cluster.k_means
- sklearn.cluster.k_means (X, n_clusters, sample_weight=None, init=’k-means++’, precompute_distances=’auto’,n_init=10, max_iter=300,verbose=False, tol=0.0001, random_state=None, copy_x=True, n_jobs=None,algorithm=’auto’, return_n_iter=False)
- 函数k_means的用法其实和类非常相似,不过函数是输入一系列值,而直接返回结果。一次性地,函数k_means会依次返回质心,每个样本对应的簇的标签,inertia以及最佳迭代次数