一.kmeans算法的简介。
K-means聚类算法也称k均值聚类算法,是集简单和经典于一身的基于距离的聚类算法。它采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为类簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。
聚类与分类的区别:

聚类:物理或抽象对象的集合分成由类似的对象组成的多个类的过程被称为聚类。由聚类所生成的簇是一组数据对象的集合,这些对象与同一个簇中的对象彼此相似,与其他簇中的对象相异。

分类:分类就是按照某种标准给对象贴标签(label),再根据标签来区分归类;事先定义好类别 ,类别数不变。

聚类是未知结果会有多少类的,即可能聚成10个类也可能聚成100个类,只是根据某些相似性条件把数据聚合在一起,当然也有让用户自定义类数目的聚类算法,但这个数目也不好定的。分类是已知一共有多少类,并明确知道该类的特点,然后把未知的按一定规则分到某一个类中
聚类聚类的数据集要比较多,这样才有东西聚成一堆一堆的。分类可以多可以少,当然数据量大才能很好地说明分类算法的优异。但实际上分类算法在确定某些规则后,你可以只有一个未知的数据也可以把它分到某一个类别当中,但聚类如果只有一个未知的数据怎么聚啊。

:本算法中可以理解为,把数据集聚类成k类,即k个簇。

质心:指各个类别的中心位置,即簇中心。

常用的聚类算法:
k-means、k-medoids、k-modes、k-medians、kernel k-means等算法。

kmeans与knn的区别

kmeans聚类算法结果分析 kmeans聚类算法简介_聚类

二.kmeans算法的核心

K-means聚类算法是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。

三. 算法实现步骤

1、首先确定一个k值,即我们希望将数据集经过聚类得到k个集合。
2、从数据集中随机选择k个数据点作为质心。
3、对数据集中每一个点,计算其与每一个质心的距离(如欧式距离),离哪个质心近,就划分到那个质心所属的集合。
4、把所有数据归好集合后,一共有k个集合。然后重新计算每个集合的质心。
5、如果新计算出来的质心和原来的质心之间的距离小于某一个设置的阈值(表示重新计算的质心的位置变化不大,趋于稳定,或者说收敛),我们可以认为聚类已经达到期望的结果,算法终止。
6、如果新质心和原质心距离变化很大,需要迭代3~5步骤。

kmeans聚类算法结果分析 kmeans聚类算法简介_kmeans聚类算法结果分析_02


上图a表达了初始的数据集,假设k=2。在图b中,我们随机选择了两个k类所对应的类别质心,即图中的红色质心和蓝色质心,然后分别求样本中所有点到这两个质心的距离,并标记每个样本的类别为和该样本距离最小的质心的类别,如图c所示,经过计算样本和红色质心和蓝色质心的距离,我们得到了所有样本点的第一轮迭代后的类别。此时我们对我们当前标记为红色和蓝色的点分别求其新的质心,如图d所示,新的红色质心和蓝色质心的位置已经发生了变动。图e和图f重复了我们在图c和图d的过程,即将所有点的类别标记为距离最近的质心的类别并求新的质心。最终我们得到的两个类别如图f。

四.伪代码

 输入:训练数据集 D=x(1),x(2),…,x(m) ,聚类簇数 k ;

  过程:函数 kMeans(D,k,maxIter) .

  1:从 D 中随机选择 k 个样本作为初始“簇中心”向量: μ(1),μ(2),…,μ(k) :

  2:repeat

  3:  令 Ci=∅(1≤i≤k)

  4:  for j=1,2,…,m do

  5:    计算样本 x(j) 与各“簇中心”向量 μ(i)(1≤i≤k) 的欧式距离

  6:    根据距离最近的“簇中心”向量确定 x(j) 的簇标记: λj=argmini∈{1,2,…,k}dji

  7:    将样本 x(j) 划入相应的簇: Cλj=Cλj⋃{x(j)} ;

  8:  end for

  9:  for i=1,2,…,k do

  10:    计算新“簇中心”向量: (μ(i))′=1|Ci|∑x∈Cix ;

  11:    if (μ(i))′=μ(i) then

  12:      将当前“簇中心”向量 μ(i) 更新为 (μ(i))′

  13:    else

  14:      保持当前均值向量不变

  15:    end if

  16:  end for

  17:  else

  18:until 当前“簇中心”向量均未更新

  输出:簇划分 C=C1,C2,…,CK

import matplotlib.pyplot as plt
from random import uniform
from math import sqrt

#创建一个数据集。
#注意:本方法创建的数据集每次运行结果都不相同
m = 60 #数据个数
data = [[],[]] #[[存储x轴数据],[存储y轴数据]]
for i in range(m):
    if i < m/3: 
        data[0].append(uniform(1,5))#随机设定
        data[1].append(uniform(1,5))
    elif i < 2*m/3:
        data[0].append(uniform(6,10))
        data[1].append(uniform(1,5))
    else:
        data[0].append(uniform(3,8))
        data[1].append(uniform(5,10))
#将创建的数据集画成散点图
plt.scatter(data[0],data[1])
plt.xlim(0,11)
plt.ylim(0,11)
plt.show()

#定义欧几里得距离
def distEuclid(x1,y1,x2,y2):
    d = sqrt((x1-x2)**2+(y1-y2)**2)
    return d

cent0 = [uniform(2,9),uniform(2,9)] #定义K=3个质心,随机赋值
cent1 = [uniform(2,9),uniform(2,9)] #[x,y]
cent2 = [uniform(2,9),uniform(2,9)]
mark = [] #标记列表
dist = [[],[],[]]#各质心到所有点的距离列表
#核心
for n in range(50):
    #计算各质心到所有点的距离
    for i in range(m):
        dist[0].append(distEuclid(cent0[0],cent0[1],data[0][i],data[1][i]))
        dist[1].append(distEuclid(cent1[0],cent1[1],data[0][i],data[1][i]))
        dist[2].append(distEuclid(cent2[0],cent2[1],data[0][i],data[1][i]))
    #对数据进行整理
    sum0_x = sum0_y = sum1_x = sum1_y = sum2_x = sum2_y = 0
    number0 = number1 = number2 = 0
    for i in range(m):
        if dist[0][i]<dist[1][i] and dist[0][i]<dist[2][i]:
            mark.append(0)
            sum0_x += data[0][i]
            sum0_y += data[1][i]
            number0 += 1
        elif dist[1][i]<dist[0][i] and dist[1][i]<dist[2][i]:
            mark.append(1)
            sum1_x += data[0][i]
            sum1_y += data[1][i]
            number1 += 1
        elif dist[2][i]<dist[0][i] and dist[2][i]<dist[1][i]:
            mark.append(2)
            sum2_x += data[0][i]
            sum2_y += data[1][i]
            number2 += 1    
    #更新质心
    cent0 = [sum0_x/number0,sum0_y/number0]
    cent1 = [sum1_x/number1,sum1_y/number1]
    cent2 = [sum2_x/number2,sum2_y/number2]

#画图
for i in range(m):
    if mark[i] == 0:
        plt.scatter(data[0][i],data[1][i],color='red')
    if mark[i] == 1:
        plt.scatter(data[0][i],data[1][i],color='blue')
    if mark[i] == 2:
        plt.scatter(data[0][i],data[1][i],color='green')     
plt.scatter(cent0[0],cent0[1],marker='*',color='red')
plt.scatter(cent1[0],cent1[1],marker='*',color='blue')
plt.scatter(cent2[0],cent2[1],marker='*',color='green')
plt.xlim(0,11)
plt.ylim(0,11)
plt.show()

五.K-means算法优缺点
优点:
1、原理比较简单,实现也是很容易,收敛速度快。
2、当结果簇是密集的,而簇与簇之间区别明显时, 它的效果较好。
3、主要需要调参的参数仅仅是簇数k。
缺点:
1、K值需要预先给定,很多情况下K值的估计是非常困难的。
2、K-Means算法对初始选取的质心点是敏感的,不同的随机种子点得到的聚类结果完全不同 ,对结果影响很大。
3、对噪音和异常点比较的敏感。用来检测异常值。
4、采用迭代方法,可能只能得到局部的最优解,而无法得到全局的最优解。