大数据-216 数据挖掘 机器学习理论 - KMeans 基于轮廓系数来选择 n_clusters
点一下关注吧!!!非常感谢!!持续更新!!!
目前已经更新到了:
- Hadoop(已更完)
- HDFS(已更完)
- MapReduce(已更完)
- Hive(已更完)
- Flume(已更完)
- Sqoop(已更完)
- Zookeeper(已更完)
- HBase(已更完)
- Redis (已更完)
- Kafka(已更完)
- Spark(已更完)
- Flink(已更完)
- ClickHouse(已更完)
- Kudu(已更完)
- Druid(已更完)
- Kylin(已更完)
- Elasticsearch(已更完)
- DataX(已更完)
- Tez(已更完)
- 数据挖掘(正在更新…)
章节内容
上节我们完成了如下的内容:
- KMeans Python 实现
- 算法验证 sklearn cluster.cluster_centers_ inertia_
案例:基于轮廓系数来选择 n_clusters
结果展示
我们通常绘制轮廓系数分布图和聚类后的数据分布图来选择我们最佳的 n_clusters
(代码在下面,这里放图)
样本数据的 KMeans 轮廓分析 簇为 2
样本数据的 KMeans 轮廓分析 簇为 4
样本数据的 KMeans 轮廓分析 簇为 6
样本数据的 KMeans 轮廓分析 簇为 8
编写代码
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# 假设X已经是定义好的数据集
# for循环,簇数从2到10,步长为2
for i in range(2, 10, 2): # 创建图形和子图fig, (ax1, ax2) = plt.subplots(1, 2)fig.set_size_inches(18, 7)# 设置第一个子图的x轴和y轴范围ax1.set_xlim([-0.1, 1])ax1.set_ylim([0, X.shape[0] + (i + 1) * 10])# 生成KMeans模型并拟合数据clusterer = KMeans(n_clusters=i, random_state=10)cluster_labels = clusterer.fit_predict(X)# 计算轮廓系数silhouette_avg = silhouette_score(X, cluster_labels)sample_silhouette_values = silhouette_samples(X, cluster_labels)print(f"簇数 = {i}, 轮廓系数均值 = {silhouette_avg}")y_lower = 10for j in range(i):# 获取第j簇的轮廓系数ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == j]ith_cluster_silhouette_values.sort()size_cluster_j = ith_cluster_silhouette_values.shape[0]y_upper = y_lower + size_cluster_jcolor = cm.nipy_spectral(float(j) / i)ax1.fill_betweenx(np.arange(y_lower, y_upper), ith_cluster_silhouette_values, facecolor=color, alpha=0.5)ax1.text(-0.05, y_lower + 0.5 * size_cluster_j, str(j))y_lower = y_upper + 10# 设置子图1的标题和标签ax1.set_title("不同簇的轮廓图")ax1.set_xlabel("轮廓系数值")ax1.set_ylabel("簇类标签")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])# 子图2:簇群的散点图colors = cm.nipy_spectral(cluster_labels.astype(float) / i)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", s=200)# 设置子图2的标题和标签ax2.set_title("簇群数据可视化")ax2.set_xlabel("第一特征的特征空间")ax2.set_ylabel("第二特征的特征空间")# 总标题plt.suptitle(f"样本数据的KMeans轮廓分析--簇数为:{i}", fontsize=14, fontweight='bold')plt.show()
具体详细的内容不展示了,上述的图片已经都有了。
重要参数-初始质心选择
在 KMeans 中有一个重要的环节,就是放置初始质心。如果有足够的时间,KMeans 一定会收敛,但 Intertia 可能收敛到局部最小值。是否能够收敛到真正的最小值很大程度上取决了质心的初始化。init 就是用来帮助我们解决初始化方式的参数。
初始质心放置的位置不同,聚类的结果很可能也会不一样,一个好的质心选择可以让 KMeans 避免更多的计算,让算法收敛稳定且更快。在之前讲解初始质心的放置时,我们是使用“随机”的方法在样本点中抽取 K 个样本作为初始质心,这种方法显然不符合稳定且更快的需求。为此,我们可以使用 random_state 参数来控制每次生成的初始质心都在相同位置,甚至可以画学习曲线来确定最优的 random_state 是哪个整数。
一个 random_state 对应一个质心随机初始化的随机数种子,如果不指定随机数种子,则 sklearn 中的 KMeans 并不会只选择一个随机模式扔出结果,而会在每个随机数种子来作为初始质心。我们可以使用参数 n_init 来选择,每个随机数种子下运行的次数。这个参数不常用到,默认 10 次,如果我们希望运行的结果来更加精确,那我们可以增加这个参数n_init的值来增加每个随机数种子下运行的次数。
然后这种方法依然是基于随机性的。为了优化选择初始质心的方法,2007 年 Arthur, David, and Sergei Vassilviskii 三人发表了论文“KMeans ++:The advantages of careful seeding”,他们开发了“KMeans++”初始化方案,使得初始质心(通常)彼此远离,以此来引导出随机初始化更可靠的结果。
在 sklearn 中,我们使用参数 init = kmeans ++ 来选择 kmeans++作为质心初始化方案。通常来说,建议保留默认的。
init
可输入 “k-means++”,“random”或者一个 n 维数组
- 初始化质心的方法,默认“k-means++”
- 输入“k-means++”:一种为 K 均值聚类选择初始聚合中心的聪明的办法,以加速收敛
- 如果输入了 N 维数组,数组的形状应该是(n_clusters,n_features)并给出初始质心
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.datasets import load_breast_cancer# 加载数据集
data = load_breast_cancer()
X = data.data# KMeans 聚类,使用 'k-means++' 初始化
cluster_01 = KMeans(n_clusters=8, init='k-means++', random_state=42).fit(X)# 输出运行的迭代次数
print(f"KMeans with 'k-means++' initialization ran for {cluster_01.n_iter_} iterations.")# 计算并输出轮廓系数(用于评估聚类效果)
sil_score_01 = silhouette_score(X, cluster_01.labels_)
print(f"Silhouette Score for 'k-means++': {sil_score_01:.4f}")# KMeans 聚类,使用 'random' 初始化
cluster_02 = KMeans(n_clusters=8, init='random', random_state=42).fit(X)# 输出运行的迭代次数
print(f"KMeans with 'random' initialization ran for {cluster_02.n_iter_} iterations.")# 计算并输出轮廓系数
sil_score_02 = silhouette_score(X, cluster_02.labels_)
print(f"Silhouette Score for 'random': {sil_score_02:.4f}")
执行结果如下图所示:
n_init
整数,默认 10
- 使用不同的质心随机初始化的种子来运行 KMeans 算法的次数,最终结果会是基于 Inertia 来计算的
- n_init 次连续运行后的最佳输出
random_state
cluster_01 = KMeans(n_clusters = 10,n_init=500).fit(X)
cluster_01.n_iter_ # 输出运行的迭代次数
silhouette_score(X,cluster_01.labels_)
cluster_02 = KMeans(n_clusters = 10,n_init=500,random_state=10).fit(X) # 每次运行结果将会一样
cluster_02.n_iter_
silhouette_score(X,cluster_02.labels_)
执行结果如下图所示:
重要参数-迭代停止
在之前描述 KMeans 的基础流程时我们提到过,当质心不再移动,KMeans 算法就会停下来。但在完成收敛之前,我们也可以使用 max_iter,最大迭代次数,或者 tol,两次迭代间 Inertia 下降的量,这两个参数来让迭代提前 停下来。有时间,当我们 n_cluster 选择不符合数据的自然分布,或者我们为了业务需求,必须要填入与数据的自然分布不合的 n_cluster,提前让迭代停下来反而能够提升模型的表现。