欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

机器学习笔记(七)k-Means

程序员文章站 2022-07-14 19:22:30
...

零、写在前面

参考资料:

一、算法原理

k-Means是一种十分简单的算法,一张图就可以解释清楚。
机器学习笔记(七)k-Means

算法流程(上图k=2):

a 原始数据
图b 随机选取k个点作为类别中心
图c 对于每个原始数据的点,把它归为最近的类别中心的那一类
图d 计算每簇点的平均值,将类别中心移至均值点
图e 对于每个原始数据的点,把它归为最近的类别中心的那一类
图f 计算每簇点点的平均值,将类别中心移至均值点
循环至收敛

二、收敛性

考虑平方误差:

E=ikxci||xμi||22μii

上面的误差可以衡量聚类结果的好坏。

实际上,k-Means算法的循环中,先固定均值向量不动,改变x的类别,再固定类别不动,改变均值向量。而每一步‘固定——改变’步骤,改变都是在做argmin(归为最近的类别中心的那一类、将类别中心移至均值点,都是尽可能地降低平方误差E)。也就是说,这一算法实际上是对平方误差E,用做坐标下降法求极值。每一步都是argmin可以保证在聚类过程中平方误差E是单调递减的,这也就确保了收敛性。

三、局部极小值

虽然保证了收敛性,但是所优化的误差函数E并不是凸函数,也就是说如果初始化不佳,k-Means有陷入局部极小值的风险。

初始化:
机器学习笔记(七)k-Means

陷入局部极小:
机器学习笔记(七)k-Means

如何解决?因为是随机初始化,再运行几次就好了。

四、实现

以下是ready-to-use的二维k-Means的python代码,使用时只需更改前两行。

from numpy import *
import matplotlib.pyplot as plt

k=2
dataMat = [[1,1],[1.5,2],[3,3],[3.5,3]]

def distEclud(vecA, vecB):
    return sqrt(sum(power(vecA - vecB, 2))) #la.norm(vecA-vecB)

def randCent(dataSet, k):
    n = shape(dataSet)[1]
    centroids = mat(zeros((k,n)))#create centroid mat
    for j in range(n):#create random cluster centers, within bounds of each dimension
        minJ = min(dataSet[:,j])
        rangeJ = float(max(dataSet[:,j]) - minJ)
        centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))
    return centroids

def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m,2)))#create mat to assign data points 
                                      #to a centroid, also holds SE of each point
    centroids = createCent(dataSet, k)
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        for i in range(m):#for each data point assign it to the closest centroid
            minDist = inf; minIndex = -1
            for j in range(k):
                distJI = distMeas(centroids[j,:],dataSet[i,:])
                if distJI < minDist:
                    minDist = distJI; minIndex = j
            if clusterAssment[i,0] != minIndex: clusterChanged = True
            clusterAssment[i,:] = minIndex,minDist**2
        for cent in range(k):#recalculate centroids
            ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]#get all the point in this cluster
            centroids[cent,:] = mean(ptsInClust, axis=0) #assign centroid to mean 
    return centroids, clusterAssment

dataMat = mat(dataMat)
myCentroids, clustAssing = kMeans(dataMat,k)

x_c, y_c = zeros(k), zeros(k)
x, y = zeros(len(dataMat)), zeros(len(dataMat))

for i in range(k):
    x_c[i] = myCentroids[i,0]
    y_c[i] = myCentroids[i,1]

for i in range(len(dataMat)):
    x[i] = dataMat[i,0]
    y[i] = dataMat[i,1]

c = zeros(len(dataMat))
for i in range(len(clustAssing)): c[i] = int(clustAssing[i,0])

plt.scatter(x_c, y_c,marker='x',c = 'black')
plt.scatter(x,y,c = c)
plt.show()

运行结果:
机器学习笔记(七)k-Means
x为聚类中心,不同颜色为不同的簇。