K-means

2020-04-15 17:11:08 浏览数 (1)

天空在高又怎样,抬起脚尖就可以离太阳就更近一点。

聚类

对于”监督学习”(supervised learning),其训练样本是带有标记信息的,并且监督学习的目的是:对带有标记的数据集进行模型学习,从而便于对新的样本进行分类。而在“无监督学习”(unsupervised learning)中,训练样本的标记信息是未知的,目标是通过对无标记训练样本的学习来揭示数据的内在性质及规律,为进一步的数据分析提供基础。对于无监督学习,应用最广的便是”聚类”(clustering)。

聚类是一种无监督的学习,它将相似的对象归到同一簇中。聚类的方法几乎可以应用所有对象,簇内的对象越相似,聚类的效果就越好。K-means算法中的k表示的是聚类为k个簇,means代表取每一个聚类中数据值的均值作为该簇的中心,或者称为质心,即用每一个的类的质心对该簇进行描述。

  聚类和分类最大的不同在于,分类的目标是事先已知的,而聚类则不一样,聚类事先不知道目标变量是什么,类别没有像分类那样被预先定义出来,所以,聚类有时也叫无监督学习。

  聚类分析试图将相似的对象归入同一簇,将不相似的对象归为不同簇,那么,显然需要一种合适的相似度计算方法,我们已知的有很多相似度的计算方法,比如欧氏距离,余弦距离,汉明距离等。事实上,我们应该根据具体的应用来选取合适的相似度计算方法。

“聚类算法”试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个“簇”(cluster),通过这样的划分,每个簇可能对应于一些潜在的概念或类别。

图解

上图是未做标记的样本集,通过他们的分布,我们很容易对上图中的样本做出以下几种划分。

当需要将其划分为两个簇时,即 k=2 时:

当需要将其划分为四个簇时,即 k=4 时:

聚类方法

1.K-means

2.DBSCAN聚类

3.DBSCAN笑脸聚类

k-means (无监督)

概念理解

kmeans算法又名k均值算法。其算法思想大致为:先从样本集中随机选取 k 个样本作为簇中心,并计算所有样本与这 k 个“簇中心”的距离,对于每一个样本,将其划分到与其距离最近的“簇中心”所在的簇中,对于新的簇计算各个簇的新的“簇中心”。

根据以上描述,我们大致可以猜测到实现kmeans算法的主要三点:   

(1)簇个数 k 的选择   

(2)各个样本点到“簇中心”的距离   

(3)根据新划分的簇,更新“簇中心”

前提准备

(1)K值的选择

k 的选择一般是按照实际需求进行决定,或在实现算法时直接给定 k 值。

(2)距离的度量

距离的度量的方法有以下几种

1.有序性距离度量

代码语言:javascript复制
(1)闵科夫斯基距离
(2)欧式距离
(3)曼哈顿距离
(4)皮尔逊系数

2.无序属性距离度量

3.混合属性距离度量

算法步骤

1、为中心向量c1, c2, …, ck初始化k个种子

2、分组:

代码语言:javascript复制
(1)将样本分配给距离其最近的中心向量
(2)由这些样本构造不相交( non-overlapping )的聚类

3、确定中心:

用各个聚类的中心向量作为新的中心

4、重复分组和确定中心的步骤,直至算法收敛。

3、算法 k-means算法

输入:簇的数目k和包含n个对象的数据库。

输出:k个簇,使平方误差准则最小。

算法步骤:

代码语言:javascript复制
1.为每个聚类确定一个初始聚类中心,这样就有K 个初始聚类中心。
2.将样本集中的样本按照最小距离原则分配到最邻近聚类
3.使用每个聚类中的样本均值作为新的聚类中心。
4.重复步骤2.3直到聚类中心不再变化。
5.结束,得到K个聚类

伪代码

为避免运行时间过长,通常设置一个最大运行轮数或最小调整幅度阈值,若达到最大轮数或调整幅度小于阈值,则停止运行。

K-means算法分析

1、k-means算法的性能分析

主要优点:

是解决聚类问题的一种经典算法,简单、快速。

对处理大数据集,该算法是相对可伸缩和高效率的。因为它的复杂度是0 (n k t ) , 其中, n 是所有对象的数目, k 是簇的数目, t 是迭代的次数。通常k < <n 且t < <n 。

当结果簇是密集的,而簇与簇之间区别明显时, 它的效果较好。

主要缺点

(1)、在簇的平均值可被定义的情况下才能使用,这对于处理符号属性的数据不适用。

(2)、在 K-means 算法中 K 是事先给定的,这个 K 值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适;

(3)、在 K-means 算法中,首先需要根据初始聚类中心来确定一个初始划分,然后对初始划分进行优化。这个初始聚类中心的选择对聚类结果有较大的影响,一旦初始值选择的不好,可能无法得到有效的聚类结果;

(4)、该算法需要不断地进行样本分类调整,不断地计算调整后的新的聚类中心,因此当数据量非常大时,算法的时间开销是非常大的;

(5)、若簇中含有异常点,将导致均值偏离严重(即:对噪声和孤立点数据敏感);

(6)、不适用于发现非凸形状的簇或者大小差别很大的簇。

K-Means算法对于不同的初始值,可能会导致不同结果。解决方法:

代码语言:javascript复制
1.多设置一些不同的初值,对比最后的运算结果)一直到结果趋于稳定结束,比较耗时和浪费资源
2.很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。这也是 K-means 算法的一个不足。有的算法是通过类的自动合并和分裂,得到较为合理的类型数目 K.

2、k-means算法的改进方法——k-prototype算法

k-Prototype算法:可以对离散与数值属性两种混合的数据进行聚类,在k-prototype中定义了一个对数值与离散属性都计算的相异性度量标准。

K-Prototype算法是结合K-Means与K-modes算法,针对混合属性的,解决2个核心问题如下:

代码语言:javascript复制
1.度量具有混合属性的方法是,数值属性采用K-means方法得到P1,分类属性采用K-modes方法P2,那么D=P1 a*P2,a是权重,如果觉得分类属性重要,则增加a,否则减少a,a=0时即只有数值属性

2.更新一个簇的中心的方法,方法是结合K-Means与K-modes的更新方法。

3、k-means算法的改进方法——k-中心点算法

k-中心点算法:k -means算法对于孤立点是敏感的。为了解决这个问题,不采用簇中的平均值作为参照点,可以选用簇中位置最中心的对象,即中心点作为参照点。这样划分方法仍然是基于最小化所有对象与其参照点之间的相异度之和的原则来执行的。

实例

由上可以看出,第一次迭代后,总体平均误差值52.25~25.65,显著减小。由于在两次迭代中,簇中心不变,所以停止迭代过程,算法停止。

代码语言:javascript复制
data = [
    [0,2],
    [0,0],
    [1,0],
    [5,0],
    [5,2]
]
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
for i in range(len(data)):
    plt.scatter(data[i][0],data[i][1],color='r')
plt.show()
代码语言:javascript复制
data_n= np.mat(data)
def center(data ,k):
    dim = np.shape(data)[1]
    cen_M = np.mat(np.zeros((k,dim)))
    for i in range(dim):
        minJ = min(data[:,i])
        rangeJ = float(max(data[:,i])-minJ)
        #print()
        #print('n')
        #print(minJ)
        cen_M[:,i] = np.mat(minJ   rangeJ * np.random.rand(k,1))
    #print(data)   
    return cen_M
#center(data_n,k)
def kmeans(data,k):
    m = np.shape(data)[0]#列的大小
    classassment = np.mat(np.zeros((m,2)))
    centerpoint = center(data,k)
    Flag = True
    conut = 0
    while Flag:
        Flag = False
        for i in range(m):
            mindis=np.inf ; minindex=-1
            for j in range(k):
                disJ = np.linalg.norm(np.array(centerpoint[j,:])-np.array(data[i,:]))
                
                if disJ < mindis:
                    mindis = disJ; minindex = j;
            if classassment[i,0] !=minindex:
                Flag = True
            classassment[i,:] = minindex,mindis**2
            #print(classassment)
            for cent in range(k):
                ptsInClust = data[np.nonzero(classassment[:,0].A==cent)[0]]#get all the point in this cluster
                centerpoint[cent,:] = np.mean(ptsInClust, axis=0)#get all the point in this cluster
                  
             
    return centerpoint,classassment
            
centerpoint,classassment=kmeans(data_n,k)            


def showCluster(dataSet, k, centroids, clusterAssment):
    '''
    数据可视化,只能画二维的图(若是三维的坐标图则直接返回1)
    '''
    numSamples, dim = dataSet.shape
    mark = ['or', 'ob', 'og', 'ok','oy','om','oc', '^r', ' r', 'sr', 'dr', '<r', 'pr']

    # draw all samples
    for i in range(numSamples):
        markIndex = int(clusterAssment[i, 0])
        plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])

    mark = ['Pr', 'Pb', 'Pg', 'Pk','Py','Pm','Pc','^b', ' b', 'sb', 'db', '<b', 'pb']
    # draw the centroids
    for i in range(k):
        plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 12)
    plt.show()
showCluster(data_n,2,centerpoint,classassment)
print(data_n)

knn k-means 对比

0 人点赞