机器学习笔记之Kmeans算法

Posted birdlove1987

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器学习笔记之Kmeans算法相关的知识,希望对你有一定的参考价值。

Kmeans算法:

优点:容易实现

缺点:可能收敛到局部最小值,在大规模数据集上的收敛速度较慢。

适用数据类型:数值型数据


算法原理:

k-means 算法接受参数 k ;然后将事先输入的n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。


算法流程:

收集数据:需要聚类的数据集。 准备数据:需要数值新数据来计算距离,也可以将标称型数据映射为二值型数据再用于距离计算。 分析数据:散点图,可视化图。 训练算法:无监督算法无此过程。 测试算法:使用Kmeans算法进行聚类,观测结果。 使用算法:可适用于任何聚类应用场景。
首先我们先给出一个演示算法的数据集,为了能直观的观测数据,我们使用散点图进行显示


PS:感觉未经过训练的人类也能将这个数据集分成四类。。是不是有点太明显了。。
然后我们来使用我们的Kmean算法
首先我们要创建一个计算的程序
def distEclud(vecA, vecB):
    return sqrt(sum(power(vecA - vecB, 2))) #计算两点间距离

然后我们要在创建一个构建质心的程序
def randCent(dataSet, k):
    n = shape(dataSet)[1]          #一条数据的维度
    centroids = mat(zeros((k,n)))  #初始化质心矩阵
    for j in range(n):             #在数据区间范围内随机初始化质心
        minJ = min(dataSet[:,j]) 
        rangeJ = float(max(dataSet[:,j]) - minJ)
        centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))
    return centroids

下面就可以编写Kmeans程序了
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):    #计算距离和创建质心都以函数引用传入
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m,2)))     #数据分类分析矩阵
                                           
    centroids = createCent(dataSet, k)     #保存数据聚类的结果
    clusterChanged = True                  #通过while循环更新质心,当数据分类不在变动就退出循环
    while clusterChanged:
        clusterChanged = False
        for i in range(m):                    #数据开始进行归类
            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
        print centroids
        for cent in range(k):                                           #根据新的数据变动更新质心
            ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
            centroids[cent,:] = mean(ptsInClust, axis=0) 
    return centroids, clusterAssment

下面我们就可以使用Kmean来对我们的数据进行分类啦:
# -*- coding: utf-8 -*-
import kMeans as km
from numpy import *
import matplotlib.pyplot as plt
datMat = mat(km.loadDataSet('DataSet.txt'))      #导入数据
myCentroids , clustAssing = km.kMeans(datMat,4)  #进行kmeans计算
plt.scatter(myCentroids[:, 0], myCentroids[:, 1], s=300, marker='o', color='r') #显示质心
plt.scatter(datMat[:,0],datMat[:,1]) #显示数据点
plt.show()

结果如下图,为了方便大家理解Kmeans的计算过程,我标记了三次质心迭代的过程,并使用箭头指示了质心移动的方向。


是不是很有趣,其实Kmeans还能做更有趣的事情呢,例如,图像内容分割。。。
先让大家看看我们使用的两张原图:




这两张图中第一张蓝胖子色彩比较简单,第二张多色彩图色彩比较富于变化。下面我们使用Kmeans来试试看
-*- coding: utf-8 -*-
import numpy as np
import PIL.Image as image
from sklearn.cluster import KMeans

#将图标转行成一个三通道矩阵,并进行归一化
def convImage(file_path):
    f = open(file_path, 'rb')      
    data = []
    img = image.open(f)  
    m, n = img.size  
    for i in range(m):
        for j in range(n): 
            x, y, z = img.getpixel((i,j))
            data.append([x/256.0, y/256.0, z/256.0])
    f.close()
    return np.mat(data), m, n  
	
	
#处理图片
imageData, row, col = convImage('rawImage.png')

k = 5  #聚类个数

result = KMeans(clusters=k).fit_predict(imageData)      

result = result.reshape([row, col])     

#重新绘制结果图片
resultImage = image.new("L",(row, col))
  
for i in range(row):    
    for j in range(col):
        resultImage.putpixel((i, j), int(256/(result[i][j]+1)))

#保存图片
resultImage.save('resultImage.png')

对于第一张蓝胖子的图片,我分别 领k =2 和k=7

看出什么来了吗?再看看第二张,我分别领k=2到12。。。

看出来了么,其实聚类的k的数量越接近原图色彩的种类和原图越像,不过。。好像没什么卵用。。没有原图好看。。。(作为一个顶级帅哥,我是外貌协会啦!!)

以上是关于机器学习笔记之Kmeans算法的主要内容,如果未能解决你的问题,请参考以下文章

机器学习笔记之Kmeans算法

菜菜的sklearn课堂笔记聚类算法Kmeans-重要参数init & random_state & n_init:初始质心怎么放更好

[机器学习与scikit-learn-23]:算法-聚类-KMeans算法的工作原理

详解聚类算法Kmeans-重要参数init & random_state & n_init:初始质心怎么放更好菜菜的sklearn课堂笔记

聚类 kmeans | 机器学习

使用 KMeans 时为每个质心获取超过 2 个坐标