# -*- encoding : utf-8 -*-
"""
@project = sklearn_learning_01
@file = 轮廓系数找最佳n_cluster
@author = wly
@create_time = 2022/12/7 23:15
"""
from sklearn.datasets import make_blobs
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
if __name__ == '__main__':
# 基于轮廓系数选择最佳的n_clusters
# 聚类完毕之后图像的分布是什么样的
# 自己创建数据集
X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)
# 包装成一个循环
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)
# 第一个图是轮廓系数图像,是由各个簇的轮廓系数组成的横向条形图
# 横向条形图的横坐标是轮廓系数取值,纵坐标是每一个样本,因为轮廓系数是对每一个样本进行计算的
# 首先设定横坐标
# 轮廓系数的取值范围在[-1, 1]之间,但目前希望轮廓系数要大于0
# 太长的横坐标不利于可视化,故只设定X轴的取值在[-0.1, 1]之间
ax1.set_xlim([-0.1, 1])
# 设定纵坐标,通常纵坐标是从0开始的,最大值取到X.shape[0]的取值
# 但为显示直观,每个簇能够排在一起,不同的簇之间能够有一定的空隙
# 故设定纵坐标的取值范围时,在X.shape[0]上,加上一个距离(n_clusters + 1) * 10,留作间隔用
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_score_avg = silhouette_score(X, cluster_labels)
print("For n_clusters = ", n_clusters)
print("The average silhouette_score is : ", silhouette_score_avg)
# 调用silhouette_samples,返回每个样本点的轮廓系数,这就是横坐标的值
sample_silhouette_values = silhouette_samples(X, cluster_labels)
# print("sample_silhouette_values shape = ", sample_silhouette_values)
# print(type(sample_silhouette_values))
# print(sample_silhouette_values.shape)
# 设定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]
# print("size_cluster_i = ", size_cluster_i)
# 这是一个簇在y轴上取值,应该是由初始值(y_lower)开始,到初始值+这个簇中样本数量结束(y_upper)
y_upper = y_lower +size_cluster_i
# print("y_upper = ", y_upper)
# colormap库中,使用小数来调用颜色的函数
# 在nipy_spectral([输入任意小数来代表一个颜色])
# 在这里希望每一个簇的颜色是不同的,需要的颜色种类刚好是循环的个数种类
# 在这里,只要能够保证,每次循环生成的小数是不同的,可以使用任意方式来获取小数
# 在这里,使用i的浮点数除以n_clusters, 在不同的i下,自然生成不同的小数
# 以此来确保所有的簇会有不同的颜色
color = cm.nipy_spectral(float(i) / n_clusters)
# 开始填充子图1中的内容
# fill_between是让一个范围内的柱状图都统一颜色的函数
# fill_betweenx的范围是纵坐标上
# fill_betweeny的范围是在横坐标
# fill_betweenx的参数应该是输入(纵坐标的下限, 纵坐标的上限, 柱状图的颜色)
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_score_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()
For n_clusters = 2
The average silhouette_score is : 0.7049787496083262
For n_clusters = 3
The average silhouette_score is : 0.5882004012129721
For n_clusters = 4
The average silhouette_score is : 0.6505186632729437
For n_clusters = 5
The average silhouette_score is : 0.56376469026194
For n_clusters = 6
The average silhouette_score is : 0.4504666294372765
For n_clusters = 7
The average silhouette_score is : 0.39092211029930857