【学习笔记】看得懂的K-means算法及其实现

算法

  1. 归类:
    聚类(clustering) 属于非监督学习 (unsupervised learning)
    无类别标记(class label)

  2. 举例:
    在这里插入图片描述

  3. K-means 算法:

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

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

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

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

    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]值的变化小于给定阈值。

  4. 举例:
    在这里插入图片描述
    将四个药分为两类

ObjectFeature1(X): weight indexFeature2(Y): pH
Medicine A11
Medicine B21
Medicine C43
Medicine D54

在这里插入图片描述
取A(1, 1)和B(2, 1)为中心点
在这里插入图片描述
矩阵第一行表示四个点到center1(A)点的距离
矩阵第二行表示四个点到center2(B)点的距离

然后看列,哪个小就归于哪类,结果如下:
在这里插入图片描述
第一类:A
第二类:B,C,D

接下来取均值重新设定中心点
c1= (1, 1)
在这里插入图片描述
更新后如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第一类:A,B
第二类:C,D

在这里插入图片描述
更新后如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第一类:A,B
第二类:C,D

结果没变,停止在这里插入图片描述

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

实现

import numpy as np

def kmeans(X, k, maxIt):
    '''
    X 数据集
    k k类
    maxIt最大迭代次数
    '''
    numPoints, numDim = X.shape     # numPoints:行数 numDim:列数

    dataSet = np.zeros((numPoints, numDim + 1))
    dataSet[:,:-1] = X

    # Initialize centroids randomly
    centroids = dataSet[np.random.randint(numPoints, size= k),:]    # 随机选取k个点作为中心点
    #centroids = dataSet[0:2,:] # 手动设置中心点为前两个点,过程将与上文相同,否则随机选取,过程可能和上文不同,但结果一定相同
    # Randomly assign labels to initial centorid
    centroids[:,-1] = range(1, k+1)     # 给中心点分类

    # Initialize book keeping vars
    iterations = 0  # 循环了多少次
    oldCentroids = None    # 旧的中心点

    # Run the main k-means algorithm
    while not shouldStop(oldCentroids, centroids, iterations, maxIt):
        print('iteration: ', iterations)
        print('dataSet: ', dataSet)
        print('centroids: ', centroids)
        # Save old centroids for convergence test. Book keeping.
        oldCentroids = np.copy(centroids)
        iterations += 1

        # Assign labels to each datapoint based on centroids
        updateLabels(dataSet, centroids)    # 更新分类标签

        # Assign centroids based on datapoint labels
        centroids = getCentroids(dataSet, k)    # 得到新的中心点

    # We can get the labels too by calling getLabels(dataSet, centroids)
    return dataSet

def shouldStop(oldCentroids, centroids, iterations, maxIt):
    if iterations > maxIt:
        return True
    return np.array_equal(oldCentroids, centroids)  # 旧中心点和新中心点是否相同,相同返回True

# Update a label for each piece of data in the dataset
def updateLabels(dataSet, centroids):
    # For each element in the dataset, chose the closest centroids
    # Make that centroid the element's label.
    numPoints, numDim = dataSet.shape   # 获取行数列数
    for i in range(0, numPoints):
        dataSet[i, -1] = getLabelFromClosestCentroid(dataSet[i, :-1], centroids)  # 对每一行最后一列赋最近中心点的label

def getLabelFromClosestCentroid(dataSetRow, centroids):
    label = centroids[0, -1]
    minDist = np.linalg.norm(dataSetRow - centroids[0, :-1])    # 初始化label和minDist
    # np.linalg.norm()计算两个向量的距离
    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

# Returns k random centroids, each of dimension n
def getCentroids(dataSet, k):
    result = np.zeros((k, dataSet.shape[1]))
    for i in range(1, k + 1):
        oneCluster = dataSet[dataSet[:, -1] == i, :-1]  # 找出label为i的值
        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:')
print(result)

iteration:  0
dataSet:  [[1. 1. 0.]
 [2. 1. 0.]
 [4. 3. 0.]
 [5. 4. 0.]]
centroids:  [[1. 1. 1.]
 [5. 4. 2.]]
minDist:  0.0
minDist:  1.0
minDist:  1.4142135623730951
minDist:  0.0
iteration:  1
dataSet:  [[1. 1. 1.]
 [2. 1. 1.]
 [4. 3. 2.]
 [5. 4. 2.]]
centroids:  [[1.5 1.  1. ]
 [4.5 3.5 2. ]]
minDist:  0.5
minDist:  0.5
minDist:  0.7071067811865476
minDist:  0.7071067811865476
final result:
[[1. 1. 1.]
 [2. 1. 1.]
 [4. 3. 2.]
 [5. 4. 2.]]
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值