K-means聚类算法理解性实现

K均值聚类算法介绍

k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法。也算是无监督学习,聚类算法中最简单的一种了。

其整体思想为,预将数据分为K组,则随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。

这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差的平方和局部最小。

接下来通过两张方式实现聚类算法,手写与库函数的调用。

K-means理解性编写

这是我关系十分不错朋友的一个作业,比较简单,但他还是不会。 真是的,他能不能想着提升一下自己啊,都大三了,还在这浪。 他们老师的目的就是理解K均值聚类算法的过程,自己写出来就行了。主要目标是补全mine_align(),与hero_move()两个函数,也是K均值里面最关键的两个部分了。以题目为例,下面说明一下。

# 商业转载请联系作者获得授权,非商业转载请注明出处。
# For commercial use, please contact the author for authorization. For non-commercial use, please indicate the source.
# 协议(License):署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
# 作者(Author):
# 链接(URL):http://begin.hjnodm.com/index.php/2021/10/18/k-means/
# 来源(Source):

import numpy as np
import matplotlib.pyplot as plt
import random
import time
 
 
class Map():
    def __init__(self, num_mine, num_hero):
        self.num_mine = num_mine
        self.num_hero = num_hero
        self.mines = []
        self.heros = []
        self.init_map()
 
    def init_map(self):
        for i in range(self.num_mine):
            x = random.random()
            y = random.random()
            self.mines.append([x, y])
        for j in range(self.num_hero):
            x1 = random.random()
            y1 = random.random()
            self.heros.append([x1, y1])
 
    def hero_move(self):
        #重新计算质心点
        for center in self.result_c:
            self.heros[center] = np.average(self.result_c[center], axis=0)
    def mine_align(self):
        #当前计算当前质心点所属的分类点有那些
        self.result_c = {}
        for i in range(self.num_hero):
            self.result_c[i] = []
        for it in self.mines:
            distance = []
            for center in self.heros:
                distance.append(np.linalg.norm(np.array(it) - np.array(center)))
            classification = distance.index(min(distance))
            self.result_c[classification].append(it)
 
    def map_visualization(self):
        tmp = np.array(self.mines)
        X = tmp[:, 0]
        Y = tmp[:, 1]
        plt.plot(X, Y, 'b*')
        tmp = np.array(self.heros)
        X = tmp[:, 0]
        Y = tmp[:, 1]
        plt.plot(X, Y, 'ro')
 
        plt.show()
 
 
def main():
    map = Map(num_mine=100, num_hero=3)
    while True:
        map.mine_align()
        map.hero_move()
        map.map_visualization()
        time.sleep(3)
 
 
if __name__ == '__main__':
    main()

mine_align()函数主要完成的就是现阶段矿石(分类点)的排列,我更喜欢称为分类。其实现的功能就是计算每一个分类点与英雄点(质心点)的距离,根据其结果,选取距离最小的作为该分类点的类别。之后就是迭代此过程,得到所有矿石所对应的英雄类别。关键的函数如下。

np.linalg.norm(np.array(it) - np.array(center))
#求两点间的距离</code></pre>

其使用了numpy库内的函数,原本的功能是求范数,实现向量范数的计算。这里单纯用于计算两个点之间的距离。

hero_move()实现的功能就是根据排列之后矿石的分类,再次计算属于原类别英雄所负责的所有分类点的平均值(距离该类别下所有矿石距离之和最近的点)来作为英雄的新坐标。

但是该模板并没有结束条件,相当于最终英雄的位置不再改变时,但是程序仍在运行。其应该是要和接下来的其他游戏程序结合起来吧,如果单纯编写K均值算法,结束条件是必须要有的。

K-means库函数编写

下面是我个人运用sklearn库函数完成的K均值算法。关键点在于求出一个数据最合适的K值。

import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
import pandas as pd
from pandas.plotting import andrews_curves

path = 'tf_idf.csv'
data = np.loadtxt(path, dtype=float, delimiter=',')
#导入数据
print(data)
k = 33
model = KMeans(n_clusters=k)
model.fit(data)
#确定分类的簇,即K值。进行拟合计算
for index, label in enumerate(model.labels_, 1):
    print("index:{}⑧⑧⑧⑧⑧label:{}".format(index, label))
#打印出每一个分类点和其所属的簇(类别)。
# for i in range(5, 36):
#     model = KMeans(n_clusters=i)
#     s = model.fit(data)
#     y_pre = s.labels_
#     ans = silhouette_score(data, y_pre)
#     print(i, ans, sep='⑧⑧⑧⑧⑧')
#关键点 求出该数据其最佳的簇的个数,即K值。
df = pd.read_csv(path, header=None)
df[3296] = model.labels_
print(df)
#新增一列,代表其标签值,即label
plt.figure()
andrews_curves(df, 3296)#一种可视化表现方式,有两种还是不错的,安德鲁曲线和雷达图,其位于pandas库内,想了解的去看一下上面导入的最后的库
plt.savefig('1.jpg')
plt.show()
#保存图片,展示。</code></pre>

K-Means追求的是簇间距离尽量大,簇内距离尽量小。常用的为轮廓系数,对于一个样本集合,它的轮廓系数是所有样本轮廓系数的平均值。轮廓系数的取值范围是[-1,1],同类别样本距离越相近不同类别样本距离越远,分数越高。但依照实际情况考虑,143条文本,其内容也相差不多。分类的簇不易过多,因此选择在5-35直接选择K的最好值。 该数据最终选择33。

在这里插入图片描述

整体小结

个人经验之谈,初学者完全可以在学习了K均值算法后,手写出其代码,重点在于理解。但如果手写,其处理数据的维度可能较低,就是简单的2维X,Y轴问题,3维数据和4维勉强可以进行处理。当对K均值有一定的了解之后,就采用库函数的方式之间调用K均值算法,同时处理的数据量也会剧增,库函数的优点同样可以帮助我们完成任务。

[原文已失效]

本程序是在python中完成,基于sklearn.cluster中的k-means聚类包来实现数据的聚类,对于里面使用的数据格式如下:(注意更改程序中的相关参数) 138 0 124 1 127 2 129 3 119 4 127 5 124 6 120 7 123 8 147 9 188 10 212 11 229 12 240 13 240 14 241 15 240 16 242 17 174 18 130 19 132 20 119 21 48 22 37 23 49 0 42 1 34 2 26 3 20 4 21 5 23 6 13 7 19 8 18 9 36 10 25 11 20 12 19 13 19 14 5 15 29 16 22 17 13 18 46 19 15 20 8 21 33 22 41 23 69 0 56 1 49 2 40 3 52 4 62 5 54 6 32 7 38 8 44 9 55 10 70 11 74 12 105 13 107 14 56 15 55 16 65 17 100 18 195 19 136 20 87 21 64 22 77 23 61 0 53 1 47 2 33 3 34 4 28 5 41 6 40 7 38 8 33 9 26 10 31 11 31 12 13 13 17 14 17 15 25 16 17 17 17 18 14 19 16 20 17 21 29 22 44 23 37 0 32 1 34 2 26 3 23 4 25 5 25 6 27 7 30 8 25 9 17 10 12 11 12 12 12 13 7 14 6 15 6 16 12 17 12 18 39 19 34 20 32 21 34 22 35 23 33 0 57 1 81 2 77 3 68 4 61 5 60 6 56 7 67 8 102 9 89 10 62 11 57 12 57 13 64 14 62 15 69 16 81 17 77 18 64 19 62 20 79 21 75 22 57 23 73 0 88 1 75 2 70 3 77 4 73 5 72 6 76 7 76 8 74 9 98 10 90 11 90 12 85 13 79 14 79 15 88 16 88 17 81 18 84 19 89 20 79 21 68 22 55 23 63 0 62 1 58 2 58 3 56 4 60 5 56 6 56 7 58 8 56 9 65 10 61 11 60 12 60 13 61 14 65 15 55 16 56 17 61 18 64 19 69 20 83 21 87 22 84 23 41 0 35 1 38 2 45 3 44 4 49 5 55 6 47 7 47 8 29 9 14 10 12 11 4 12 10 13 9 14 7 15 7 16 11 17 12 18 14 19 22 20 29 21 23 22 33 23 34 0 38 1 38 2 37 3 37 4 34 5 24 6 47 7 70 8 41 9 6 10 23 11 4 12 15 13 3 14 28 15 17 16 31 17 39 18 42 19 54 20 47 21 68 22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值