kmeans算法代码解析

Kmeas原理


1、从数据集D中随机取k个元素,作为k个簇的各自的中心(质心)。
2、分别计算剩下的元素到k个簇中心的相似度,并将其归属为和其做相似的簇。
3、根据聚类结果,重新计算k个簇各自的中心,计算方法是取簇中所有元素各自维度的算术平均数。
4、重复2-3,直到满足停止条件。
停止条件通常为:聚类结果几乎不再发生变化,或者达到一定的迭代次数。
 

import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# 计算欧拉距离
def calcDis(dataSet, centroids, k):
    clalist = []
    for data in dataSet:
        diff = np.tile(data, (k, 1)) - centroids  
# 相减   (np.tile(a,(2,1))就是把a先沿x轴复制1倍,即没有复制,仍然是 [0,1,2]。 再把结果沿y方向复制2倍得到array([[0,1,2],[0,1,2]]))
        squaredDiff = diff ** 2  # 平方
        squaredDist = np.sum(squaredDiff, axis=1)  # 和  (axis=1表示行)
        distance = squaredDist ** 0.5  # 开根号
        clalist.append(distance)
    clalist = np.array(clalist)  # 返回一个每个点到质点的距离len(dateSet)*k的数组
    return clalist


# 计算质心
def classify(dataSet, centroids, k):
    # 计算样本到质心的距离
    clalist = calcDis(dataSet, centroids, k)
    # 分组并计算新的质心
    minDistIndices = np.argmin(clalist, axis=1)  # axis=1 表示求出每行的最小值的下标
    print(minDistIndices)
    newCentroids = pd.DataFrame(dataSet).groupby(
        minDistIndices).mean()  # DataFramte(dataSet)对DataSet分组,groupby(min)按照min进行统计分类,mean()对分类结果求均值
    newCentroids = newCentroids.values

    # 计算变化量
    changed = newCentroids - centroids
    return changed, newCentroids


# 使用k-means分类
def kmeans(dataSet, k):
    # 随机取质心
    centroids = random.sample(dataSet, k)

    # 更新质心 直到变化量全为0
    changed, newCentroids = classify(dataSet, centroids, k)
    while np.any(changed != 0):
        changed, newCentroids = classify(dataSet, newCentroids, k)

    centroids = sorted(newCentroids.tolist())  # tolist()将矩阵转换成列表 sorted()排序

    # 根据质心计算每个集群
    cluster = []
    clalist = calcDis(dataSet, centroids, k)  # 调用欧拉距离
    minDistIndices = np.argmin(clalist, axis=1)
    for i in range(k):
        cluster.append([])
    for i, j in enumerate(minDistIndices):  # enymerate()可同时遍历索引和遍历元素
        cluster[j].append(dataSet[i])

    return centroids, cluster


# 创建数据集
def createDataSet():
    return [[1, 1], [1, 2], [2, 1], [6, 4], [6, 3], [5, 4],[1,5],[6,4],[3,5]]

import torch
if __name__ == '__main__':
    featuress= createDataSet()
    centroids, cluster = kmeans(featuress, 3)
    print('质心为:%s' % centroids)
    print('集群为:%s' % cluster)
    for i in range(len(featuress)):
        plt.scatter(featuress[i][0], featuress[i][1], marker='o', color='green', s=40, label='原始点')
        #  记号形状       颜色      点的大小      设置标签
    for j in range(len(centroids)):
        plt.scatter(centroids[j][0], centroids[j][1], marker='x', color='red', s=50, label='质心')
plt.show()

流程演示图 

定义一组数据集

# 创建数据集
def createDataSet():
    return [[1, 1], [1, 2], [2, 1], [6, 4], [6, 3], [5, 4],[1,5],[6,4],[3,5]]

以上述代码为例,k=3,即生成3组

因为每组都有1个质心,有3个质心。

首先,在数据集中随机采样3个点,作为质心。centroids是质心数组

centroids = random.sample(dataSet, k)

调用classfiy函数计算最终的质心

然后,不断调用classfiy函数,更新质心。直到质心不再改变

 # 更新质心 直到变化量全为0
    changed, newCentroids = classify(dataSet, centroids, k)
    while np.any(changed != 0):
        changed, newCentroids = classify(dataSet, newCentroids, k)

对于任何一次的classfiy函数调用过程中,调用欧拉计算对所有点计算到每个质心的距离,得到clalist数组。

 # 计算样本到质心的距离
    clalist = calcDis(dataSet, centroids, k)

如下图,9行3列。一行表示一个点,一列表示一个质点,(1,2)表示第1个点到第2个质点的距离。

 利用以下代码求得每行的最小值的坐标,即a点到3个质点哪个距离最短。

minDistIndices = np.argmin(clalist, axis=1)  # axis=1 表示求出每行的最小值的下标

 按照每组分类,得到3个大类。每类中包含距离该质心相对近的点。

将每类的点的横纵坐标取平均值,如以下图

newCentroids = pd.DataFrame(dataSet).groupby(
        minDistIndices).mean()  # DataFramte(dataSet)对DataSet分组,groupby(min)按照min进行统计分类,mean()对分类结果求均值

行表示3个大类,列表示横纵坐标。此时,3个新质点的坐标是(2.5,3)(5.75,3.75)(1.0,2.6667)

计算changed,看看新旧质心有没有改变。如果改变了,说明旧质心不是最终点,如果没改变,说明旧质心是最终点。同时,可以print可视化一下。

 changed = newCentroids - centroids
    print('旧质点: %s ' % centroids)
    print('新质点:%s ' % newCentroids)
    print('changed %s ' %changed)

以上就是这一层的调用classfiy过程

通过质心找到各所属集群

在质心不再改变时,即找到3个最终质心后。将最后一层的classfiy调用时生成的clalist数组按照之前的方法找到所属的质点,即a点到3个质点哪个距离最短。将该点最终加入到所属群中。

minDistIndices = np.argmin(clalist, axis=1)
    for i in range(k):
        cluster.append([])
    for i, j in enumerate(minDistIndices):  # enymerate()可同时遍历索引和遍历元素
        cluster[j].append(dataSet[i])

以下是最终结果

最终质心为(1.33333,1.333333)、(2,5)(5.75,3.75)

而集群1为(1,1)(1,2) (2,1) 集群2为(1,5)(3,5)集群3为(6,4)(6,3)(5,4)(6,4)

 在稍大点数据集的聚类效果

在1500个样本中随机采样出100个点,使用kmeans聚类出3个所属类别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值