上篇文章为大家介绍了我们常用的聚类算法Kmenas算法,也为大家整理了一点小案例,今天为大家继续分享我们Kmenas算法,对Kmenas算法来说,如何确定簇数K值是一个至关重要的问题,为了解决这个问题,通常会选用探索法,即给定不同的k值下,对比某些评估指标的变动情况,进而选择一个比较合理的k值,在这我们上篇文章给大家推荐了三种方法(簇内离差平方和拐点法,轮廓系数法和间隔统计量法),接下来我们分别看看这三种方法是如何实现的:
Kmenas算法基础公式:
拐点法
簇内离差平方和拐点法的思想很简单,就是在不同的k值下计算簇内离差平方和,然后通过可视化的方法找到"拐点"所对应的k值,J为Kmeans算法的目标函数,随着簇数量的增加,簇中的样本量会越来越少,进而导致目标函数J的值也会越来越小,通过可视化方法,重点关注的是斜率的变化,当斜率由大突然变小时,并且之后的斜率变化缓慢,则认为突然变化的点就是寻找的目标点,因为继续随着簇数K的增加,聚类效果不再有大的变化。
接下来我们就验证这个方法,随机生成三组二元正态分布数据,首先基于该数据绘制散点图,如下代码:
import pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeans#随机生成三组二元正态分布随机数np.random.seed(1234)mean1 = [0.5,0.5]cov1 = [[0.3,0],[0,0.3]]x1,y1 = np.random.multivariate_normal(mean1,cov1,1000).Tmean2 = [0,8]cov2 = [[0.3,0],[0,0.3]]x2,y2 = np.random.multivariate_normal(mean2,cov2,1000).Tmean3 = [8,4]cov3 = [[1.5,0],[0,1]]x3,y3 = np.random.multivariate_normal(mean3,cov3,1000).T#绘制三组数据的散点图plt.scatter(x1,y1)plt.scatter(x2,y2)plt.scatter(x3,y3)plt.show()
如上图,虚拟出来的数据呈现出三个簇,接下来基于这个虚拟数据,使用拐点法绘制簇的个数与总的簇内离差平方和之间的折线图,确定最终的k值,代码如下:
#构造自定义函数,用于绘制不同的k值和对应总的簇内离差平方和的折线图def k_SSE(X,clusters): #选择连续的K种不同的值 K= range(1,clusters+1) #构建空列表用于存储总的簇内离差平方和 TSSE= [] for k in K: #用于存储各个簇内离差平方和 SSE = [] kmeans = KMeans(n_clusters=k) kmeans.fit(X) #返回簇标签 labels = kmeans.labels_ #返回簇中心 centers = kmeans.cluster_centers_ #计算各簇样本的离差平方和,并保存到列表中 for label in set(labels): SSE.append(np.sum((X.loc[labels==label,]-centers[label,:])**2)) #计算总的簇内离差平方和 TSSE.append(np.sum(SSE)) #中文和负号正常显示 plt.rcParams['font.sans-serif'] = 'SimHei' plt.rcParams['axes.unicode_minus'] =False #设置绘画风格 plt.style.use('ggplot') #绘制K的个数与TSSE的关系 plt.plot(K,TSSE,'b*-') plt.xlabel('簇的个数') plt.ylabel('簇内离差平方和之和') # plt.show()#将三组数据集汇总到数据框中X = pd.DataFrame(np.concatenate([np.array([x1,y1]),np.array([x2,y2]),np.array([x3,y3])],axis=1).T)k_SSE(X,15)
如上图,当簇的个数为3时,形成了一个明显的"拐点