zoukankan      html  css  js  c++  java
  • sklearn中的KMeans算法

      1、聚类算法又叫做“无监督分类”,其目的是将数据划分成有意义或有用的组(或簇)。这种划分可以基于我们的业务需求或建模需求来完成,也可以单纯地帮助我们探索数据的自然结构和分布。

      2、KMeans算法将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上来看是簇是一组一组聚集在一起的数据,在一个簇中的数据就认为是同一类。簇就是聚类的结果表现。簇中所有数据的均值通常被称为这个簇的“质心”(centroids)。在一个二维平面中,一簇数据点的质心的横坐标就是这一簇数据点的横坐标的均值,质心的纵坐标就是这一簇数据点的纵坐标的均值。同理可推广至高维空间。

      3、KMeans追求的是‘簇内差异小,簇间差异大’。

      所有簇的簇内平方和相加,就得到了整体平方和,又叫做total inertia。Total Inertia越小,代表着每个簇内样本越相似,聚类的效果就越好。因此KMeans追求的是,求解能够让Inertia最小化的质心。实际上,在质心不断变化不断迭代的过程中,总体平方和是越来越小的。

      注:损失函数本质是用来衡量模型的拟合效果的,只有有着求解参数需求的算法,才会有损失函数。Kmeans不求解什么参数,它的模型本质也没有在拟合数据,而是在对数据进行一种探索,故Kmeans不存在损失函数,Inertia更像是Kmeans的评估指标,而不是损失函数。

      除了模型本身的效果之外,我们还使用另一种角度来度量算法:算法复杂度。算法的复杂度分为时间复杂度和空间复杂度,时间复杂度是指执行算法所需要的计算工作量,常用大O符号表述;而空间复杂度是指执行这个算法所需要的内存空间。如果一个算法的效果很好,但需要的时间复杂度和空间复杂度都很大,那我们将会权衡算法的效果

      和所需的计算成本。和KNN一样,KMeans算法是一个计算成本很大的算法。

      聚类模型的结果不是某种标签输出,并且聚类的结果是不确定的,其优劣由业务需求或者算法需求来决定,并且没有永远的正确答案。

      用inertia作为衡量指标并不合适,一个较小的Inertia究竟有没有达到模型的极限,能否继续提高;Inertia的计算太容易受到特征数目的影响,数据维度很大的时候,Inertia的计算量会陷入维度诅咒之中,计算量会爆炸,不适合用来一次次评估模型;Inertia还会受到超参数K的影响,随着K越大,Inertia注定会越来越小,但这并不代表模型的效果越来越好了;Inertia对数据的分布有假设,它假设数据满足凸分布并且它假设数据是各向同性的,即是说数据的属性在不同方向上代表着相同的含义,但是现实中的数据往往不是这样,所以使用Inertia作为评估指标,会让聚类算法在一些细长簇,环形簇,或者不规则形状的流形时表现不佳。

      4、KMeans模型评估指标,分两种:

      标签已知时,如果拥有真实标签,我们更倾向于使用分类算法。但不排除我们依然可能使用聚类算法的可能性。如果我们有样本真实聚类情况的数据,我们可以对于聚类算法的结果和真实结果来衡量聚类的效果。常用的有以下三种方法:

      互信息分;V-measure(基于条件上分析的一系列直观度量);调整兰德系数

      真实标签未知时,轮廓系数(评价簇内的稠密程度(簇内差异小)和簇间的离散程度(簇外差异大)来评估聚类的效果),卡林斯基-哈拉巴斯指数(Calinski-Harabaz Index,简称CHI,也被称为方差比标准),戴维斯-布尔丁指数(Davies-Bouldin)以及权变矩阵(Contingency Matrix)

      轮廓系数的范围是(-1,1),值越接近1表示样本与自己所在的簇中的样本很相似,并且与其他簇中的样本不相似;当样本点与簇外的样本更相似的时候,轮廓系数就为负;当轮廓系数为0时,则代表两个簇中的样本相似度一致,两个簇本应该是一个簇。在sklearn中,我们使用模块metrics中的类silhouette_score来计算轮廓系数,它返回的是一个数据集中,所有样本的轮廓系数的均值。但我们还有同在metrics模块中的silhouette_sample,它的参数与轮廓系数一致,但返回的是数据集中每个样本自己的轮廓系数。

      基于轮廓系数选择最佳的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)

      fig,ax1=plt.subplots(1)

      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()

      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=4

      #创建一个画布,画布上有一行两列两个图

      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生成所有样本点轮廓系数的均值

      #需要输入两个参数,特征矩阵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轴的初始取值

      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]

      #一个簇在y州的取值是由初始值(y_lower)开始,到初始值加上这个簇中的样本数量结束(y_upper)

      y_upper = y_lower + size_cluster_i

      #用i的浮点数除以n_clusters,在不同的i下生成不同的小数,以确保所有的簇都有不同的颜色

      color = cm.nipy_spectral(float(i)/n_clusters)

      #fill_between是让一个范围的柱状图都统一颜色的函数,

      #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

      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])

      #开始处理第二个图,首先获取新的颜色,由于没有循环需要一次性生成多个小数来获取多个颜色

      #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("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()无锡妇科医院 http://www.bhnnk120.com/

      #将上述过程包装称循环

      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"

      "with n_clusters = %d" % n_clusters),fontsize=14, fontweight='bold')

      plt.show()

      5、初始质心(init)

      init:可输入**“k-means++”,“random"或者一个n维数组**。这是初始化质心的方法,默认"k-means++"。

      输入"kmeans++”:一种为K均值聚类选择初始聚类中心的聪明的办法(使得初始质心通常彼此远离),以加速收敛。

      "random"下,如果不指定随机数种子,则sklearn中的K-means并不会只选择一个随机模式扔出结果,而会在每个随机数种子下运行多次,并使用结果最好的一个随机数种子来作为初始质心。可以使用参数n_init来选择每个随机数种子下运行的次数,这个参数不常用到,默认10次,如果我们希望运行的结果更加精确,那我们可以增加这个参数n_init的值来增加每个随机数种子下运行的次数。然而这种方法依然是基于随机性的。

      如果输入了n维数组,数组的形状应该是(n_clusters,n_features)并给出初始质心。

      6、max_iter & tol:让迭代停下来

      当质心不再移动,Kmeans算法就会停下来,但在完全收敛之前,可以使用max_iter(最大迭代次数)或者tol(两次迭代间Inertia下降的量),这两个参数来让迭代提前停下来。数据量特别大时可以使用。

      max_iter:整数,默认300,单次运行的k-means算法的最大迭代次数

      tol:浮点数,默认1e-4,两次迭代间Inertia下降的量,如果两次迭代之间Inertia下降的值小于tol所设定的值,迭代就会停下

  • 相关阅读:
    python学习之- 内置函数
    python学习之- 生成器/迭代器
    python学习之-- 装饰器
    python基础之
    Python基础之 一 字符编码及转换
    为什么utf8占用3个字节
    Python基础之 一 文件操作
    IIS6与IIS7中如何设置文件过期
    分布式缓存系统Memcached简介与实践
    Log4net
  • 原文地址:https://www.cnblogs.com/djw12333/p/11411182.html
Copyright © 2011-2022 走看看