非监督学习—K-means算法聚类学习笔记

非监督学习: 无类别标记的

一、 K-means 算法:

1. Clustering 中的经典算法,数据挖掘十大经典算法之一

2. 参数k

已知参数 k ;然后将事先输入的n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。

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

4. 算法描述:

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

5. 算法流程

    输入:类的数量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]值的变化小于给定阈值。

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

二、举例


将上述四个药片归为两类:

蓝色为药片,五角星为随机选取的中心点,四个点到c1(1,1)的距离分别为0、1、3.61、5 ; 四个点到c2(2,1)的距离为1、0、2.83、4.24;


得到第一个点为一类,第234个为第二类,再重新找中心点。

新的中心点:c1>>(1,1); c2>>(11/3,8/3)  新的图示如下:





完成分类,迭代停止。(停止条件:分类不变,或分类变化小于一个值,或指定迭代次数)

三、python实现

import numpy as np


def kmeans(x, k, maxIt):    # maxIt是迭代次数

    numPoints, numDim = x.shape     # 传入的行数

    dataSet = np.zeros((numPoints, numDim + 1))       # 多添加一列,作为标记
    dataSet[:,:-1] = x      # 除了最后一列其他的和x一样

    centroids = dataSet[np.random.randint(numPoints, size= k), :]    # 选出k个行数,作为中心点
    centroids[:, -1] = range(1, k+1)

    iterations = 0           # 第多少次循环
    oldCentroids = None     # 旧的中心点

    while not shouldstop(oldCentroids, centroids, iterations, maxIt):
        print("iteration: ", iterations)
        print("dataSet: \n", dataSet)
        print("centroids: \n", centroids)
        oldCentroids = np.copy(centroids)
        iterations += 1

        updataLabels(dataSet, centroids)      # 重新归类label

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

    return dataSet


def shouldstop(oldCentroids, centroids, iterations, maxIt):
    if iterations > maxIt:                              # 是否到预设迭代次数
        return True
    return np.array_equal(oldCentroids, centroids)      # 比较值中心点是否相等


def updataLabels(dataSet, centroids):

    numPoints, numDim = dataSet.shape
    for i in range(0, numPoints):       # 计算
        dataSet[i, -1] =  getLabelFromClosestCentroid(dataSet[i,:-1], centroids)    # 对比距离,返回最近中心点的标记


def getLabelFromClosestCentroid(dataSetRow, centroids):

    label = centroids[0, -1]
    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("-"*10)
    print("minDistance: ", minDist)
    return label


def getCentroids(dataSet, k):
    result = np.zeros((k, dataSet.shape[1]))    # 初始化 shape[1] 为列数
    for i in range(1, k+1):                     # 将所有标签相同的点找出来,求均值
        oneCluster = dataSet[dataSet[:, -1] == i, :-1]      # 等于某一列的所有标签找出来
        result[i - 1, :-1] = np.mean(oneCluster, axis=0)    # 求均值,赋到除了最后一列的所有,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:\n", result)


猜你喜欢

转载自blog.csdn.net/xyu66/article/details/80050391