K-Means聚类算法

俗话说“物以类聚,人以群分”,在地理学中有个概念叫做空间相关性,距离越是近的两个地理对象越是相关。这个思想很好的诠释了下面我们介绍的一个非监督分类算法,K-Means聚类算法,如何把相似的事物关联到一起呢?就通过事物的距离来判断,当然这个距离不仅仅局限于欧氏距离。
如何判断两个事物之间的距离呢?这就需要一个参照系,比如说两棵树之间的距离,那么放到坐标系中赋予x,y坐标系就能很容易计算出距离。那如果是抽象的事物呢?对,抽取特征,抽取这个事物的特征组成n维的特征向量,这就是赋予这个事物参照系了。以图像分类为例吧,抽取灰度值后组成特征向量,但是图像这么多我该跟那个图像比较距离呢?不用惆怅当然不会图像之间两两比较了。
举个愉快的例子说一下这个算法,话说派别划分少林寺与峨眉派,怎么区分这两个派别的人呢?看性别啊,衣服啊,武功路数啊,武器啊。。。。淡定,没错你说的这么都是特征,但是计算机不知道啊,实际上我们只需要看他们的老大就是主持,看看这些人的特征跟哪个老大类似,那么他肯定就是那个派别的。没错,但是我怎么知道谁是老大,拿破仑说的好不想当主持的和尚不是好和尚,主持也是和尚是由和尚中选出来的,那么这个老大我们也照做,随机选两个人作为老大,然后所有的点分别跟这个老大比,跟谁最近这个点就标记为哪个门派,然后在把所有标记好的弟子特征取均值,再把以这个均值作为老大的标配所以相应门派的人向老大看起,然后一直迭代下去,直到老大的特征不再改变,说明选上了正在的老大找到了真正的门派传承人。这个时候,就能体现出“近朱者赤近墨者黑”这句话的含义了,跟两个正在的老大对比,离谁近就跟谁。这个时候门派的划分终于化好了。
K-Means聚类算法,特点是简单,速度快,但是缺点也明显,容易陷入局部最优,在做实验过程中经常得到的值不是全局最优解,并且得设置到底聚多少类。这个就比较尴尬了,拿咏春来说吧,肯定谁离叶问最近谁就是咏春派的,但是当我们把类别设置为两类的时候,冷不丁多出来一个李小龙独创一派。
这里写图片描述
言归正传,在我做实验的过程中,图像数据分为建筑用地与森林两类,最好的一次聚类中,准确率达到81%,这个结果很是棒,因为总共有100样例,正负各50张,k-means算法达到比朴素贝叶斯还要高的准确度。
这里写图片描述
源码如下,欢迎指正交流:


# -*- coding: utf-8 -*-
"""
Created on Fri Mar  2 08:55:57 2018

@author: Administrator
"""

import numpy as np
def kmeans(X,k,maxIt):
    numPoints,numDim=X.shape
    dataSet=np.zeros((numPoints,numDim+1))
    dataSet[:,:-1]=X

    #随机初始化中心点
    centroids=dataSet[np.random.randint(numPoints,size=k),:]

    #随机的赋值标签
    centroids[:,-1]=range(k)

    iterations=0
    oldCentroids=np.zeros((k,numDim+1))

    #运行kmeans算法
    while not shouldStop(oldCentroids,centroids,iterations,maxIt):
        print("iteration:\n",iterations)
        print("dataset:\n",dataSet)
        print("centroids:\n",centroids)

        #保存老中心点用于比较
        oldCentroids=np.copy(centroids)
        iterations+=1

        #基于中心点更新lable
        updateLabels(dataSet,centroids)

        #重新更新中心点
        centroids=getCentroids(dataSet,k)
    return dataSet

def shouldStop(oldCentroids,centroids,iterations,maxIt):
    """
    当迭代次数大于最大迭代次数时候停止
    当中心点不在更新的时候迭代停止
    """
    if iterations>maxIt:
        return True
    return np.array_equal(centroids,oldCentroids)
    #return False

def updateLabels(dataSet,centroids):
    """
    根据中心点进行更新lables
    """
    numPoints,numDim=centroids.shape
    distanceMatric=[]
    for i in range(0,numPoints):
        distanceMatric.append(np.linalg.norm(dataSet[:,:-1]-np.atleast_2d(centroids[i,:-1]),axis=1))
    distanceMatric=np.atleast_2d(distanceMatric)
    labelIndex=np.argmin(distanceMatric,axis=0)
    dataSet[:,-1]=labelIndex.T


def getCentroids(dataSet,k):
    centroids=[]
    for i in range(k):
        mean=np.mean(dataSet[dataSet[:,-1]==i,:-1],axis=0)
        centroids.append(np.hstack((mean,[i])))

    return np.atleast_2d(centroids)




import h5py 

def loadDataSet():
    '''
    加载图片数据集
    '''
    pictureSet=[];pictureClasses=[]
    with h5py.File(r'F:\python_project\ml_dl\NBClassfiyLand\bdata\Land.h5') as h5f:
        forest=h5f['forest'][:]
        urban=h5f['urban'][:]
        pictureSet=np.vstack((forest,urban))
        pictureClasses=[0]*50+[1]*50
    return pictureSet,pictureClasses

#x1 = np.array([1, 1])
#x2 = np.array([2, 1])
#x3 = np.array([4, 3])
#x4 = np.array([5, 4])
#testX = np.vstack((x1, x2, x3, x4))
testX,testY=loadDataSet()
result = kmeans(testX, 2, 1000)
print(np.sum(np.equal(testY,result[:,-1]))/100.)


这里写图片描述
关注我的公共号,去github上领取源码与数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值