K均值聚类算法(Kmeans)讲解及源码实现

K均值聚类算法(Kmeans)讲解及源码实现


算法核心

K均值聚类的核心目标是将给定的数据集划分成K个簇,并给出每个数据对应的簇中心点。算法的具体步骤描述如下。

  1. 数据预处理,如归一化、离群点处理等。
  2. 随机选取K个簇中心,记为 μ 1 ( 0 ) , μ 2 ( 0 ) , . . . , μ k ( 0 ) \mu_1^{(0)},\mu_2^{(0)},...,\mu_k^{(0)} μ1(0),μ2(0),...,μk(0)
  3. 定义代价函数 J ( c , μ ) = m i n μ m i n c Σ i = 1 M ∣ ∣ x i − μ c i ∣ ∣ 2 J(c,\mu)=min_{\mu}min_{c}\Sigma_{i=1}^M||x_i-\mu_{c_i}||^2 J(c,μ)=minμmincΣi=1Mxiμci2
  4. t = 0 , 1 , 2 , . . . t=0,1,2,... t=0,1,2,...为迭代步数,重复下面过程直到 J J J收敛
  • 对于每一个样本 x i x_i xi,将其分配到距离最近的簇 c i ( t ) ← a r g m i n k ∣ ∣ x i − μ k ( t ) ∣ ∣ 2 c_i^{(t)}\leftarrow argmin_k ||x_i-\mu_k^{(t)}||^2 ci(t)argminkxiμk(t)2
  • 对于每一个类簇 k k k重新计算该类中心 μ k ( t + 1 ) ← a r g m i n μ Σ i : x i ( t ) = k ∣ ∣ x i − μ ∣ ∣ 2 \mu_k^{(t+1)}\leftarrow argmin_{\mu}\Sigma_{i:x_i^{(t)}=k}||x_i-\mu||^2 μk(t+1)argminμΣi:xi(t)=kxiμ2

K K K均值算法在迭代时,假设当前损失函数 J J J没有达到最小值,那么首先固定簇中心 { μ k } \{\mu_k\} {μk},调整每个样例 x i x_i xi所属的类别 c i c_i ci来让 J J J函数减少;
然后固定 { c i } \{c_i\} {ci},调整簇中心 { μ k } \{\mu_k\} {μk}使 J J J减少。
这两个过程交替循环, J J J单调递减:当 J J J递减到最小值时, μ k {\mu_k} μk c i {c_i} ci也同时收敛。

源码实现(含可视化)

导入包

import numpy as np
import matplotlib.pyplot as plt

数据预处理

设置地图尺寸

# map 100*100
high = 100
width = 100

创建随机数据
每一条数据的格式为 ( x 坐 标 , y 坐 标 , 类 别 ) (x坐标,y坐标,类别) (x,y,),列表初始化为0,类别序数间隔1递增

data = np.random.rand(100, 2)
data = data * [high, width]
data = np.hstack((data, np.zeros([100, 1])))

定义簇数目

# count of classes
classes = 5

定义距离函数,此处我们使用欧氏距离

def distance(point1, center):
    return np.sqrt((point1[0] - center[0]) ** 2 + (point1[1] - center[1]) ** 2)

定义从类别到颜色的映射函数,即
类 别 ∗ 255 / 总 类 别 数 类别*255/总类别数 255/

def color(i):
    global classes
    return i * 255. / classes

定义主函数

先将plt设置为连续作图模式
然后随机挑选簇中心点,并加入到中心点数组 c e n t e r s _ d a t a centers\_data centers_data

if __name__ == '__main__':
    plt.ion()
    # select center randomly
    centers = np.random.randint(0, 100, [classes])
    centers_data = []
    for i in range(classes):
        data[i][2] = i
        centers_data.append(data[i])

先画散点图,且暂停0.5秒以显示迭代中的聚类情况。

    while True:
        colors = [color(x) for x in data[:, 2]]
        plt.scatter(data[:, 0], data[:, 1], c=colors)
        plt.pause(0.5)

先后依次迭代更新每个点所对应的簇,和每个簇的中心点。

        # caculate nearest center
        for i in range(100):
            distances = np.array([distance(data[i], center_data) for center_data in centers_data])
            i_class = np.argmin(distances)
            data[i][2] = i_class
        # caculate new center
        new_centers_data = np.zeros([classes, 2])
        new_centers_count = np.zeros([classes])
        for j in range(5):
            for i in range(100):
                if data[i][2] == j:
                    new_centers_count[j] += 1
                    new_centers_data[j] += data[i][0:2]

计算五个簇的中心点位置先后变化的最大值,其值小于1e-4(可自定义)时,跳出循环,停止迭代。

		new_centers_data /= np.array([new_centers_count]).T
        dist = np.max([distance(new_centers_data[i], centers_data[i]) for i in range(classes)])
        print('max distance ', dist)
        if dist < 1e-4:
            break

在每次迭代的最后更新中心点数据

		centers_data = new_centers_data

最后关闭连续作图模式,并展示最后的图画,打印结束。

	plt.ioff()
    plt.show()
    print('kmeans completed.')

效果

命令行

max distance  28.36595846126929
max distance  7.136259328045152
max distance  3.533885366585787
max distance  2.153654229308223
max distance  0.0
kmeans completed.

可视化过程

第1次迭代
在这里插入图片描述
第2次迭代
在这里插入图片描述
第3次迭代
在这里插入图片描述
第4次迭代
在这里插入图片描述

全部代码

import numpy as np
import matplotlib.pyplot as plt

# map 100*100
high = 100
width = 100
# create random data
data = np.random.rand(100, 2)
data = data * [high, width]
data = np.hstack((data, np.zeros([100, 1])))
# count of classes
classes = 5


def distance(point1, center):
    return np.sqrt((point1[0] - center[0]) ** 2 + (point1[1] - center[1]) ** 2)


def color(i):
    global classes
    return i * 255. / classes


if __name__ == '__main__':
    plt.ion()
    # select center randomly
    centers = np.random.randint(0, 100, [classes])
    centers_data = []
    for i in range(classes):
        data[i][2] = i
        centers_data.append(data[i])
    while True:
        colors = [color(x) for x in data[:, 2]]
        plt.scatter(data[:, 0], data[:, 1], c=colors)
        plt.pause(0.5)
        # caculate nearest center
        for i in range(100):
            distances = np.array([distance(data[i], center_data) for center_data in centers_data])
            i_class = np.argmin(distances)
            data[i][2] = i_class
        # caculate new center
        new_centers_data = np.zeros([classes, 2])
        new_centers_count = np.zeros([classes])
        for j in range(5):
            for i in range(100):
                if data[i][2] == j:
                    new_centers_count[j] += 1
                    new_centers_data[j] += data[i][0:2]
        new_centers_data /= np.array([new_centers_count]).T
        dist = np.max([distance(new_centers_data[i], centers_data[i]) for i in range(classes)])
        print('max distance ', dist)
        if dist < 1e-4:
            break
        centers_data = new_centers_data
    plt.ioff()
    plt.show()
    print('kmeans completed.')

  • 1
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值