机器学习-Kmeans算法

学习彭亮《深度学习基础介绍:机器学习》课程


归类

聚类(clustering) 属于非监督学习 (unsupervised learning),无类别标记(class label)
这里写图片描述

K-means 算法

Clustering 中的经典算法,数据挖掘十大经典算法之一
算法接受参数 k ;然后将事先输入的n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。

算法思想

以空间中k个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果

算法描述

  1. 适当选择c个类的初始中心;
  2. 在第k次迭代中,对任意一个样本,求其到c各中心的距离,将该样本归到距离最短的中心所在的类;
  3. 利用均值等方法更新该类的中心值;
  4. 对于所有的c个聚类中心,如果利用(2)(3)的迭代法更新后,值保持不变,则迭代结束,否则继续迭代。

算法流程

输入:k, data[n];

  1. 选择k个初始中心点,例如c[0]=data[0],…c[k-1]=data[k-1];
  2. 对于data[0]….data[n], 分别与c[0]…c[k-1]比较,假定与c[i]差值最少,就标记为i;
  3. 于所有标记为i点,重新计算c[i]={ 所有标记为i的data[j]之和}/标记为i的个数;即重新计算均值。
  4. 重复(2)(3),直到所有c[i]值的变化小于给定阈值。

算法优缺点

  • 优点:速度快,简单
  • 缺点:最终结果跟初始点选择相关,容易陷入局部最优,需直到k值

实例

假设有四个药品,知道他们的重量指标和PH指标,需要把它们分为两类。
这里写图片描述

在坐标轴中描出是个药品:
这里写图片描述

第一次迭代
K=2,随机选取两个点,计算所有点到这两个点的距离,假设选中的点位两个星形的点
这里写图片描述

D矩阵中第一行表示所有点到左边这个星的距离,第二行表示所有点到右边这个星的距离
这里写图片描述

G矩阵表示把左边的星化为一类,剩下的三个点化为一类
这里写图片描述
C1的中心即为左边星的坐标,同时更新第二类的中心点为C2


第二次迭代
星形表示当前分类中心
这里写图片描述

这里写图片描述
这里写图片描述
所以从左到右前两个为第一类,后两个为第二类,更新中心点坐标
这里写图片描述


第三次迭代

这里写图片描述

这里写图片描述

这里写图片描述

此时分类不再更新=>结束,得到结果为:
这里写图片描述


代码

#coding=utf-8
# @Author: yangenneng
# @Time: 2018-01-20 15:53
# @Abstract:Kmeans算法

import numpy as np

'''
# X:数据集
# k:分为多少类
# maxIt:最多迭代多少次
'''
def kmeans(X,k,maxIt):
    # 返回行、列  即数据集的形状
    numPoints,numDim=X.shape
    # 给数据集多加一列
    dataSet = np.zeros((numPoints,numDim+1))
    # 把前numDim列=X
    dataSet[:,:-1] = X
    # # 随机选取K个中心点
    # centroids=dataSet[np.random.randint(numPoints,size=k),:]

    # 故意选择中心点为前两个,对应上述例子
    centroids=dataSet[0:2,:]

    # 初始化中心点的最后一列
    centroids[:,-1]=range(1,k+1)

    iterations=0
    # 储存旧的中心点
    oldCentroids=None

    # 只要不停止(新、旧中心点不一致)或(循环了maxIt次,当前为iterations次)
    while not shouldStop(oldCentroids,centroids,iterations,maxIt):
        print "循环到第"+str(iterations)+"次:\n"
        print "数据集dataSet:\n",dataSet
        print "中心点centroids:\n",centroids

        # 不能直接赋值,否则会同步更新,所以用复制
        oldCentroids=np.copy(centroids)
        iterations += 1
        # 更新数据集所属标签
        updateLables(dataSet,centroids)
        # 更新中心点
        centroids=getCentroids(dataSet,k)

    return dataSet

# 是否停止
def shouldStop(oldCentroids,centroids,iterations,maxIt):
    if iterations>maxIt:
        return True
    return np.array_equal(oldCentroids,centroids)

def updateLables(dataSet,centroids):
    numPoints,numDim=dataSet.shape
    for i in range(0,numPoints):
        dataSet[i,-1]=getLableFormClosetCentroid(dataSet[i,:-1],centroids)
'''
#  dataSetRow 当前行
#  centroids  中心点
# 返回当前点和那个中心点最近,即标签
'''
def getLableFormClosetCentroid(dataSetRow,centroids):
    label=centroids[0,-1]
    # np.linalg.norm算两个向量的距离
    minDist=np.linalg.norm(dataSetRow-centroids[0,:-1])

    for i in range(1,centroids.shape[0]):
        # 不算最后一列 因为最后一列是标签
        dist=np.linalg.norm(dataSetRow-centroids[i,:-1])
        if dist<minDist:
            minDist=dist
            label=centroids[i,-1]

    print "minDist:",minDist
    return label

def getCentroids(dataSet,k):
    result=np.zeros((k,dataSet.shape[1]))
    for i in range(1,k+1):
        # 把所有分类为i的找出来
        oneCluster=dataSet[dataSet[:,-1]==i,:-1]
        result[i-1,:-1]=np.mean(oneCluster,axis=0)
        result[i-1, -1]=i

    return result

'''
# ..........................主程序...............................
'''
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))

result=kmeans(testX,2,10)
print "final result:",result

这里写图片描述
这里写图片描述

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YEN_CSDN/article/details/79114677
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭