机器学习算法-K-means聚类,算法-k-means聚类


引文: k均值算法是一种聚类算法,所谓聚类,他是一种无监督学习,将相似的对象归到同一个蔟中。蔟内的对象越相似,聚类的效果越好。聚类和分类最大的不同在于,分类的目标事先已知,而聚类则不一样。因为其产生的结果和分类相同,而只是类别没有预先定义。

算法的目的: 使各个样本与所在类均值的误差平方和达到最小(这也是评价K-means算法最后聚类效果的评价标准)

K-均值聚类

  • 优点:容易实现
  • 缺点:可能收敛到局部最小值,在大规模数据上收敛较慢
  • 适合数据类型:数值型数据

伪代码

#创建k个点作为起始质心(经常随机选择)
#当任意一个点的蔟分配结果发生变化时
    #对数据集中的每个数据点
        #对每个质心
            #计算质心到数据点之间的距离
        #将数据点分配到距其最近的蔟
    #对每个蔟,计算蔟中所有点的均值并将均值作为质心

代码实现

因为我们用到的是数值类型的数据,这里编写一个加载数据集的函数,返回值是一个矩阵形式。
下面代码应写在一个py文件里,我这里写在kMeans.py文件中。

文件的头部引入numpy

from numpy import *

数据集加载代码

# 加载数据集文件,没有返回类标号的函数
def loadDataSet(fileName):
    dataMat = []
    openfile = open(fileName)    
    for line in openfile.readlines():
        curLine = line.strip().split('\t')
        floatLine = map(float,curLine)
        dataMat.append(floatLine)
    return dataMat

因为在k均值算法中要计算点到质心的距离,所以这里将距离计算写成一个函数,计算欧几里得距离公式:
d=(x2x1)2+...+(z2z1)2

函数代码如下:

# 计算两个向量的欧氏距离
def distEclud(vecA,vecB):
    return sqrt(sum(power(vecA-vecB,2)))

接下来初始化k个蔟的质心函数centroid

# 传入的数据时numpy的矩阵格式
def randCent(dataMat, k):
    n = shape(dataMat)[1]
    centroids = mat(zeros((k,n)))  
    for j in range(n):
        minJ = min(dataMat[:,j]) # 找出矩阵dataMat第j列最小值
        rangeJ = float(max(dataMat[:,j]) - minJ) #计算第j列最大值和最小值的差
        #赋予一个随机质心,它的值在整个数据集的边界之内
        centroids[:,j] = minJ + rangeJ * random.rand(k,1) 
    return centroids #返回一个随机的质心矩阵

K-means算法

#k-均值算法
def kMeans(dataMat,k,distE = distEclud , createCent=randCent):
    m = shape(dataMat)[0]    # 获得行数m
    clusterAssment = mat(zeros((m,2))) # 初试化一个矩阵,用来记录簇索引和存储误差                               
    centroids = createCent(dataMat,k) # 随机的得到一个质心矩阵蔟
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        for i in range(m):    #对每个数据点寻找最近的质心
            minDist = inf; minIndex = -1
            for j in range(k): # 遍历质心蔟,寻找最近的质心    
                distJ1 = distE(centroids[j,:],dataMat[i,:]) #计算数据点和质心的欧式距离
                if distJ1 < minDist: 
                    minDist = distJ1; minIndex = j
            if clusterAssment[i,0] != minIndex:
                clusterChanged = True
            clusterAssment[i,:] = minIndex,minDist**2
        print centroids
        for cent in range(k):    #更新质心的位置
            ptsInClust = dataMat[nonzero(clusterAssment[:,0].A==cent)[0]]    
            centroids[cent,:] = mean(ptsInClust, axis=0) 
    return centroids, clusterAssment

测试:

dataMat = mat(loadDataSet('testSet.txt'))
kMeans(dataMat,4)

输出结果:

===================

[[-3.66087851 2.30869657]
[ 3.24377288 3.04700412]
[ 2.52577861 -3.12485493]
[-2.79672694 3.19201596]]
[[-3.78710372 -1.66790611]
[ 2.6265299 3.10868015]
[ 1.62908469 -2.92689085]
[-2.18799937 3.01824781]]
[[-3.53973889 -2.89384326]
[ 2.6265299 3.10868015]
[ 2.65077367 -2.79019029]
[-2.46154315 2.78737555]]

===================

上面的结果给出了四个质心。可以看出,经过3次迭代之后K-均值算法收敛。质心会保存在第一个返回值中,第二个是每个点的簇分布情况。

附件:
上面测试的数据集为:

1.658985    4.285136
-3.453687   3.424321
4.838138    -1.151539
-5.379713   -3.362104
0.972564    2.924086
-3.567919   1.531611
0.450614    -3.302219
-3.487105   -1.724432
2.668759    1.594842
-3.156485   3.191137
3.165506    -3.999838
-2.786837   -3.099354
4.208187    2.984927
-2.123337   2.943366
0.704199    -0.479481
-0.392370   -3.963704
2.831667    1.574018
-0.790153   3.343144
2.943496    -3.357075
-3.195883   -2.283926
2.336445    2.875106
-1.786345   2.554248
2.190101    -1.906020
-3.403367   -2.778288
1.778124    3.880832
-1.688346   2.230267
2.592976    -2.054368
-4.007257   -3.207066
2.257734    3.387564
-2.679011   0.785119
0.939512    -4.023563
-3.674424   -2.261084
2.046259    2.735279
-3.189470   1.780269
4.372646    -0.822248
-2.579316   -3.497576
1.889034    5.190400
-0.798747   2.185588
2.836520    -2.658556
-3.837877   -3.253815
2.096701    3.886007
-2.709034   2.923887
3.367037    -3.184789
-2.121479   -4.232586
2.329546    3.179764
-3.284816   3.273099
3.091414    -3.815232
-3.762093   -2.432191
3.542056    2.778832
-1.736822   4.241041
2.127073    -2.983680
-4.323818   -3.938116
3.792121    5.135768
-4.786473   3.358547
2.624081    -3.260715
-4.009299   -2.978115
2.493525    1.963710
-2.513661   2.642162
1.864375    -3.176309
-3.171184   -3.572452
2.894220    2.489128
-2.562539   2.884438
3.491078    -3.947487
-2.565729   -2.012114
3.332948    3.983102
-1.616805   3.573188
2.280615    -2.559444
-2.651229   -3.103198
2.321395    3.154987
-1.685703   2.939697
3.031012    -3.620252
-4.599622   -2.185829
4.196223    1.126677
-2.133863   3.093686
4.668892    -2.562705
-2.793241   -2.149706
2.884105    3.043438
-2.967647   2.848696
4.479332    -1.764772
-4.905566   -2.911070

相关内容