机器学习算法学习【1】——K-means聚类算法

聚类与分类的区别

分类:类别是已知的,通过对已知类别的数据进行训练和学习,找到这些不同类的特征,再对未知类别的数据进行分类。属于监督学习。

聚类:事先不知道数据会分为几类,通过聚类分析将数据聚合成几个群体。聚类不需要对数据进行训练和学习。属于无监督学习。

关于监督学习和无监督学习,这里给一个简单的介绍:一般而言,是否有监督,就看输入数据是否有标签,输入数据有标签,则为有监督学习,否则为无监督学习。

K-means 聚类原理简述

聚类算法有很多种,K-Means 是聚类算法中的最常用的一种,算法最大的特点是简单,好理解,运算速度快,但是只能应用于连续型的数据,并且一定要在聚类前需要手工指定要分成几类。

K-Means 聚类算法的大致思想就是“物以类聚,人以群分”:

1、首先输入 k 的值,即我们指定希望通过聚类得到 k 个分组;
2、从数据集中随机选取 k 个数据点作为初始大佬(质心);
对集合中每一个小弟,计算与每一个大佬的距离,离哪个大佬距离近,就跟定哪个大佬;
3、这时每一个大佬手下都聚集了一票小弟,这时候召开选举大会,每一群选出新的大佬(即通过算法选出新的质心);
4、如果新大佬和老大佬之间的距离小于某一个设置的阈值(表示重新计算的质心的位置变化不大,趋于稳定,或者说收敛),可以认为我们进行的聚类已经达到期望的结果,算法终止;
5、如果新大佬和老大佬距离变化很大,需要迭代3~5步骤。

上述内容引用自知乎大佬【打工人小飞】的文章5 分钟带你弄懂 K-means 聚类

大佬通过一个生动形象的例子清晰的解释了K-means算法的大致思路,这里我通过这个例子写了一个伪K-means算法供大家参考

import random
from math import sqrt

class K_means:
    def __init__(self,K:int,dataset,iter:int):
        """K为聚类数,dataset为数据集,iter为迭代次数"""
        self.K=K
        self.dataset=dataset
        self.verbose=iter

    def cal_distance(self,point1:list,point2:list)->float:
        """计算两点距离"""
        sumOfSquare = (point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2
        return sqrt(sumOfSquare)

    def average_points(self,points_arr:list)->tuple:
        """计算均值点"""
        x_ = sum(point[0] for point in points_arr) / len(points_arr)
        y_ = sum(point[1] for point in points_arr) / len(points_arr)
        return (x_, y_)

    def train(self):
        # 随机生成K个中心点的种子
        # seeds=[0,1]
        seeds=random.sample(range(0,len(self.dataset)),self.K)
        # 将随机选择的K个点作为初始中心点
        init_centre = []
        for i, seed in enumerate(seeds):
            init_centre.append(self.dataset[seed])
        print('初始中心点_train', init_centre)
        # 将初始中心点外的点作为'小弟'
        bubs = [self.dataset[i] for i in range(len(self.dataset)) if i not in seeds]
        print('bubs_train', bubs)
        self.iteration(init_centre=init_centre,init_bubs=bubs)



    def iteration(self,init_centre,init_bubs):
        """init_boss=[(),(),()···()]  """
        centre=init_centre
        bubs=init_bubs
        for verb in range(1,self.verbose+1):
            cluster = [[] for i in range(self.K)]
            bubs_distance = []  # 每个小弟到其他中心点的距离,如3个中心点3个小弟则[[a1,a2,a3],[b1,b2,b3],[c1,c2,c3]]
            # print('centre_%d'%verb,centre)
            # print('分配1_%d' %verb,bubs)
            for bub in bubs:
                bub_to_centre = []  # 单个小弟到其他中心点的距离[dist1,dist2,···,distK]
                for cen in centre:
                    bub_to_centre_dist = self.cal_distance(bub, cen)  # 两点间的距离
                    bub_to_centre.append(bub_to_centre_dist)
                bubs_distance.append(bub_to_centre)
            # print('每个小弟到其他中心点的距离', bubs_distance)

            rearrange = []
            # 将距小弟最近的中心点的小标记作一个列表
            for bub_dist in bubs_distance:
                close_boss = bub_dist.index(min(bub_dist))
                # print(close_boss)
                rearrange.append(close_boss)
            # 更新最新中心点
            new_centre=list(set(self.dataset)-set(bubs))
            # 将最新中心点分配到各个组/簇
            for i, bos in enumerate(new_centre):
                cluster[i].append(bos)
            # 根据列表重新分配组/簇
            for bub, i in zip(bubs, rearrange):
                cluster[i].append(bub)
            # print('cluster1_%d'%verb,cluster)
            # 重新更新小弟集
            tmp_bubs=[]
            # 如果一个簇仅有一个元素那么这个元素就是一个大哥/中心点,有多个元素的簇将取其均值点作为新的大哥/中心点
            # 之前的大哥将被下方至小弟集中
            for clus in cluster:
                # print('clus',clus[0])
                if len(clus) != 1:
                    # print('clus',clus)
                    for cl in clus:
                        tmp_bubs.append(cl)
            bubs=tmp_bubs
            # print('分配2_%d'%verb,bubs)

            print('第%d轮簇'%verb,cluster)
            boss=[]
            # 计算新的中心点放入cluster
            for clus in cluster:
                new_boss = self.average_points(clus)
                # print(new_boss)
                boss.append(new_boss)
            # print('boss',boss)
            centre=boss

if __name__ == '__main__':
    Dataset = [[0, 0], [1, 2], [3, 1], [8, 8], [9, 10], [10, 7]]
    Dataset = [tuple(point) for point in Dataset]
    K_mean=K_means(2,Dataset,3)
    K_mean.train()

# 初始中心点_train [(9, 10), (10, 7)]
# bubs_train [(0, 0), (1, 2), (3, 1), (8, 8)]
# 第1轮簇 [[(9, 10), (8, 8)], [(10, 7), (0, 0), (1, 2), (3, 1)]]
# 第2轮簇 [[(9, 10), (8, 8), (10, 7)], [(0, 0), (1, 2), (3, 1)]]
# 第3轮簇 [[(9, 10), (8, 8), (10, 7)], [(0, 0), (1, 2), (3, 1)]]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值