K-Means K均值算法python实现 (包括绘图)

算法梗概

K-Means算法(K均值)是一种基于姓心的无监督聚类算法,用于把样本集中的对象分配到n个簇中,该算法的基本步骤:

1:随机产生n个中心点(n需要事先给定,n是多少,最后产生的簇就是多少)

2:计算每个样本点与中心点的距离(该距离不一定是我们通常认为的欧式距离,但在本例中,我将用欧式距离来计算)

3:把每一个点分配给距离最近的中心点

4:重新计算每个簇的中心点,并重复第2步

算法实现

直接上代码


import random as rd
import numpy as np
import matplotlib.pyplot as plt

X = np.array([[0, 0],
              [1, 1],
              [2, 1],
              [4, 3],
              [5, 3],
              [5, 4],
              [6, 5],
              [1, 4],
              [1, 5],
              [1, 6]])


def K_Means(X, n):
    # 随机生成n个中心点(用数组储存)
    C_new = []  # 新的中心点
    C_old = []  # 旧的中心点
    style_color = ['r', 'y', 'b', 'c', 'm']  # 颜色类型
    style_symbol = ['o', '^', 'h', 'd', 'D']  # 点的图形
    current_color = []  # 每个点应该的颜色类型
    pause_time = 0.5  # 画完一个点之后的暂停时间

    for i in range(n):
        C_new.append(list(rd.choice(X)))
    print("随机生产的中心点有:", C_new)
    # while(新的中心点不全等于旧的中心点):
    while C_new != C_old:
        plt.xlim(-1, 9)  # 初始化画布坐标轴范围
        plt.ylim(-1, 9)
        # 分别计算每个点到n个中心点的距离
        index = []  # 对应中心点在C_new中的下标
        '''========把X中的点(和中心点)依次画出来(只适用与2维数组)=========='''
        if not current_color:
            x = np.array(X).transpose().tolist()
            for i in range(X.shape[0]):
                plt.plot(x[0][i], x[1][i], 'go')
                plt.pause(pause_time)
        else:
            x = np.array(X).transpose().tolist()
            for i in range(X.shape[0]):
                plt.plot(x[0][i], x[1][i], 'o'+style_color[current_color[i]])
            plt.pause(pause_time)

        # 绘制中心点
        y = np.array(C_new).transpose().tolist()
        for i in range(len(C_new)):
            plt.plot(y[0][i], y[1][i], 'D'+style_color[i])
            plt.pause(pause_time)
        '''==============================================='''
        for i in range(X.shape[0]):
            dis = [dist(X[i], C_new[j]) for j in range(len(C_new))]  # 因为C_new是列表类型,他没有shape方法,只能用len
            # 把最小距离的中心点的下标存入数组(一样大的话随便存)
            index.append(dis.index(min(dis)))
        print(index)
        '''==============把属于同一个中心点的点染色============='''
        current_color = index.copy()  # 把索引复制给c_c
        x = np.array(X).transpose().tolist()
        for i in range(X.shape[0]):
            plt.plot(x[0][i], x[1][i], 'o' + style_color[current_color[i]])
            plt.pause(pause_time)
        del x
        '''==============================================='''
        # 把新中心点赋值(copy)给旧中心点
        C_old = C_new.copy()
        C_new = []
        # 分别取出相同下标的点集合,重新计算中心点并赋值给新的中心点
        index = np.array(index)
        for i in range(index.max() + 1):
            points = X[np.where(index == i)]
            C_new.append(list(center(points)))
        print("新的中心点:", C_new)
        '''===============判断是否应该结束绘图===================='''
        if C_new != C_old:
            plt.clf()
        '''================================================'''
    print('分类完毕')
    plt.show()


# 计算距离
def dist(X1, X2):  # X1 X2 必须都是数组类型
    X1 = np.array(X1)
    X2 = np.array(X2)
    s = sum((X1 - X2) ** 2) ** 0.5
    print(X1, "和", X2, "之间的距离为:", round(s, 2))
    return s


# 计算中心点
def center(X):
    # 次优解决方案!
    Y = X[0]
    for i in range(1, X.shape[0]):
        Y = Y + X[i]
    return Y / len(X)


K_Means(X, 3)


这段代码可以直接复制到自己的电脑里面跑一下,可能会出现一开始随机产生的中心点有两个相同的bug,我懒得debug了哈哈哈

被===== ====== 括起来的代码都是为了绘制出图写的,大家可以直接删掉,不影响代码的运行(如果要删的话不要忘记删掉前面的plt.xlim(),plt.ylim()和最后的plt.show()。

因为第一次使用matplotlib,对他的一些方法不太了解,所以写出来的代码非常冗长,如果不需要绘图的话,只需要大概40多行就可以完成任务。

代码分析:

计算两个点之间距离的代码:

def dist(X1, X2):  # X1 X2 必须是数组类型
    X1 = np.array(X1) # 为了初始化点的类型
    X2 = np.array(X2)
    s = sum((X1 - X2) ** 2) ** 0.5
    print(X1, "和", X2, "之间的距离为:", round(s, 2))
    return s

如两个点:x1:[1,2],x2:[3,4]
先计算两个点各个分量之间的差
x1 - x2 = [-2,-2]
再计算两个差的平方和再开发

计算中心点

def center(X):
   Y = X[0]
   for i in range(1, X.shape[0]):
       Y = Y + X[i]
   return Y / len(X)

n个点的中心点,如点:[2,3][4,4][5,6]
它的中心点是:([2,3]+[4,4]+[6,8])/3 = [4,5]
其中上面的分母3是点的个数,如果有4个点那就应该除以4了。我认为K-均值算法的均值就体现在这里。

到这里两个最基本的方法已经写好了,接下来过一下这个算法

K-Means(X,n)

其中的X是样本点集,n是你需要的簇的量,值的注意的是,X是一个二维数组,他每一行代表一个点。

我认为这段代码唯一需要说明一下的就是 :

index = []  # 对应中心点在C_new中的下标

这一小段莫名其妙的代码了。其他的地方我都用注释的方式写出了用处。

这段代码是啥意思呢?或者说这个index[]有啥用呢?他其实就是每一个样本点的类标号集合。比如我的样本中心点C_new里面有x,y,z这三个中心点,那index[]里面第0个元素的值(假设它为1),那他的意思就是X里面的第0个点离样本中心点C_new内下标为1的中心点距离最近

这个非常有用,如果要绘图的话,这段代码也可以派上用场

最后

这是我写的第一个博客,我也是一个刚入门的程序猿,如果有什么地方不对的,或者有更好的实现方法,欢迎留言!😁

ps:关于绘图还没有讲,不过原理十分简单,思想就是给每一个点都做一个标记,在遍历每个点的时候给每个点按照标记“覆盖”一层颜色(本质上是在原来的点的基础上在画一个新的点)。

效果图:菱形是中心点位置,在自己电脑上运行的话,它会以动画的方式呈现
菱形是中心点位置,在自己电脑上运行的话,它会以动画的方式呈现

  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值