Python机器学习——K-Means聚类

来源:互联网 发布:淘宝酷卡体育东西正嘛 编辑:程序博客网 时间:2024/06/03 21:23

  样本集D={x⃗ 1,x⃗ 2,...,x⃗ N},假设聚类的簇划分C={C1,C2,...,CK}。k均值算法的目标是最小化平方误差:

err=k=1Kx⃗ iCk||x⃗ iμk||22
  其中,μ⃗ k=1Ckx⃗ iCkx⃗ i是簇Ck的均值向量。上式刻画了簇类样本围绕簇均值向量的紧密程度,err越小,则簇内样本簇均值向量越紧密。
  现在要求最优化问题:
minCk=1Kx⃗ iCk||x⃗ iμk||22
  该问题的求解需要考察样本集合D的所有可能的簇划分。k均值算法采用贪心算法,通过迭代优化来近似求解。其原理为:k均值算法首先假设一组向量作为所有簇的簇均值限量,然后根据假设的簇均值向量给出了数据集D的一个簇划分,再根据这个簇划分来计算真实的簇均值向量。

  • 如果真实的簇均值向量等于假设的簇均值向量,则说明假设正确。根据假设簇均值向量给出的数据集D的一个簇划分确实是元问题的解。
  • 如果真实的簇均值向量等不于假设的簇均值向量,则可以将真实的簇均值向量作为新的假设簇均值向量,继续求解。
      这里的一个关键就是:给定假设簇均值向量,如何计算出数据集D的一个簇划分?k均值算法的策略是:样本距离哪个簇的簇均值向量最近,则该样本就划归到那个簇。

  下面给出k均值算法:

  • 输入

    • 样本集D={x⃗ 1,x⃗ 2,...,x⃗ N}
    • 聚类簇数K
  • 输出:簇划分C={C1,C2,...,CK}
  • 算法步骤
    • 从数据集D中随机选取K个样本作为初始均值向量{μ⃗ 1,μ⃗ 2,...,μ⃗ K}
    • 重复迭代直到算法收敛,迭代内容如下:
      • 初始化阶段:取Ck=,k=1,2,...,K
      • 划分阶段:令i=1,2,...,N
        • 计算x⃗ i的簇标记如下:
          λi=argmink||x⃗ iμ⃗ k||2,k1,2,...,K
        • 然后将样本x⃗ i划入相应的簇:
          Cλi=Cλi(x⃗ i)
      • 重计算阶段:计算μ⃗ ′′k
        μ⃗ k=1|Ck|x⃗ iCkx⃗ i
      • 终止条件判断:
        • 如果对所有的k1,2,,K,都有μ⃗ k=μ⃗ k,则算法收敛,终止迭代
        • 否则重赋值μ⃗ k=μ⃗ k

Python实战


  KMeans是scikit-learn提供的聚类算法模型,其原型为:

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=1,algorithm=’auto’)

参数

  • n_clusters:一个整数,指定分类簇的数量
  • init:一个字符串,指定初始均值向量的策略。可以为如下:
  • K-Means++:该初始化策略选择的初始均值向量相互之间距离都较远,它的效果较好
  • random:从数据集中随机选取K个样本作为初始均值向量
  • 或者提供一个数组,数组的形状为(n_clusters.n_features),该数组作为初始均值向量k均值算法总能够收敛,但是其收敛情况高度依赖于初始化的向量。有可能收敛于局部极小值。因此通常都是用多组初始向量来计算若干次,选择其中最优的一次。而k-means++策略选择的初始均值向量可以在一定程度上解决这个问题。
  • n_init:一个整数,指定了k均值算法运行的次数。每一次都会选择一组不同的初始化均值向量,最终算法会选择最佳的分类簇作为最终的结果。
  • max_iter:一个整数,指定了单轮k均值算法中,最大的迭代次数。算法总的最大迭代次数为max_iter * n_init。
  • precompute_distance:可以为布尔值或字符串’auto’。该参数指定是否提前计算好样本之间的距离(如果提前计算距离,则需要更多的内存,但是算法会运行的更快)。
  • auto:如果n_samples * n_clusters > 12 million,则不提前计算
  • True:总是提前计算
  • False :总是不提前计算
  • tol:一个浮点数,指定了算法收敛的阈值
  • n_jobs:一个正数,指定任务并行时的CPU数量。如果为-1则使用所有可用的CPU
  • verbose:一个整数,如果为0,则不输出日志信息;如果为1,则每隔一段时间打印一次日志信息;如果大于1,则打印日志信息更频繁
  • random_state:一个整数或一个RandomState实例,,或者为None
  • 如果为整数,则它指定了随机数生成器的种子
  • 如果为RandomState实例,则它指定了随机数生成器
  • 如果为None,则使用默认的随机数生成器
  • copy_x:布尔值,主要用于precompute_distance=True的情况
  • 如果为True,则预计算距离的时候,并不修改原始数据
  • 如果为False,则预计算距离的时候,会修改原数数据用于节省内存,但后当算法结束的时候,会将原数据返回。但是可能会因为浮点数的表示,会有一些精度误差

属性

  • cluster_centers_:给出分类簇的均值向量
  • labels_:给出了每个样本所属的簇的标记
  • inertia_:给出了每个样本距离它最近的簇中心的距离之和

方法

  • fit(X[,y]):训练模型
  • fitpredict(X[,y]):训练模型并预测每个样本所属的簇,它等价于先调用fit方法,后调用predict方法
  • predict:预测样本所属的簇
  • score(X[,y]):给出了样本距离一个簇中心的偏移量的相反数。

#-*-coding:gbk-*-'''Created on 2017年9月15日@author: '''from sklearn import clusterfrom sklearn.metrics import adjusted_rand_scoreimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.datasets.samples_generator import make_blobsfrom matplotlib.pyplot import plot"""    产生数据"""def create_data(centers,num=100,std=0.7):    X,labels_true = make_blobs(n_samples=num,centers=centers, cluster_std=std)    return X,labels_true"""    数据作图"""def plot_data(*data):    X,labels_true=data    labels=np.unique(labels_true)    fig=plt.figure()    ax=fig.add_subplot(1,1,1)    colors='rgbycm'    for i,label in enumerate(labels):        position=labels_true==label        ax.scatter(X[position,0],X[position,1],label="cluster %d"%label),        color=colors[i%len(colors)]    ax.legend(loc="best",framealpha=0.5)    ax.set_xlabel("X[0]")    ax.set_ylabel("Y[1]")    ax.set_title("data")#     plt.show()"""    测试数据"""def test_KMeans(*data):    X,labels_true=data    clst=cluster.KMeans()    clst.fit(X)    predicted_labels=clst.predict(X)    print("ARI:%s"% adjusted_rand_score(labels_true, predicted_labels))    print("Sum center distance %s"%clst.inertia_)"""    考察簇的数量的影响"""def test_KMeans_nclusters(*data):    X,labels_true=data    nums=range(1,50)    ARIs=[]    Distances=[]    for num in nums:        clst=cluster.KMeans(n_clusters=num)        clst.fit(X)        predicted_labels=clst.predict(X)        ARIs.append(adjusted_rand_score(labels_true, predicted_labels))         Distances.append(clst.inertia_)     fig=plt.figure()    ax=fig.add_subplot(1,2,1)    ax.plot(nums,ARIs,marker="+")    ax.set_xlabel("n_clusters")    ax.set_ylabel("ARI")    ax=fig.add_subplot(1,2,2)    ax.plot(nums,Distances,marker="o")    ax.set_xlabel("n_clusters")    ax.set_ylabel("inertia")    fig.suptitle("KMeans")#     plt.show()"""    考察运行次数和初始中心选择策略的影响"""    def test_KMeans_n_init(*data):    X,labels_true=data    nums=range(1,50)    fig=plt.figure()    ARIs_k=[]    Distances_k=[]    ARIs_r=[]    Distances_r=[]    for num in nums:        clst=cluster.KMeans(n_init=num,init='k-means++')        clst.fit(X)        predicted_labels=clst.predict(X)        ARIs_k.append(adjusted_rand_score(labels_true, predicted_labels))        Distances_k.append(clst.inertia_)        clst=cluster.KMeans(n_init=num,init='random')        clst.fit(X)        predicted_labels=clst.predict(X)        ARIs_r.append(adjusted_rand_score(labels_true, predicted_labels))        Distances_r.append(clst.inertia_)    ax=fig.add_subplot(1,2,1)    ax.plot(nums,ARIs_k,marker="+",label="k-means++")    ax.plot(nums,ARIs_r,marker="+",label="random")    ax.set_xlabel("n_init")    ax.set_ylabel("ARI")    ax.set_ylim(0,1)    ax.legend(loc="best")    ax=fig.add_subplot(1,2,2)    ax.plot(nums,Distances_k,marker="o",label="k-means++")    ax.plot(nums,Distances_r,marker="o",label="random")    ax.set_xlabel("n_init")    ax.set_ylabel("inertia")    ax.legend(loc="best")    fig.suptitle("KMeans")    plt.show()centers=[[1,1],[2,2],[1,2],[10,20]]X,labels_true=create_data(centers, 1000, 0.5)test_KMeans(X,labels_true)plot_data(X,labels_true)test_KMeans_nclusters(X,labels_true)test_KMeans_n_init(X,labels_true)

这里写图片描述

这里写图片描述

可以看到,当n_clusters=4时,ARI指数最大,因为确实是从四个中心点产生的簇。而inertia_在n_clusters=1时最大,因为产生的测试数据有三个中心点较为接近,一个中心点较远。因此如果指定簇的数量为1,及所有的样本都属于一个簇,确实样本离簇中心的距离之和最大。

这里写图片描述

可以看到ARI指数和inertia_总距离随着n_init震荡,因此这两项指标与n_init影响不是很大,而且随机选择和使用'k-means++'策略选择初始中心向量,对于聚类效果的影响也不大。
原创粉丝点击