当前位置: 首页 > news >正文

数据挖掘经典十大算法_K-Means算法

数据挖掘经典十大算法_K-Means算法

一、从故事理解K-Means Clustering Algorithm

1.有四个牧师去郊区布道,一开始牧师们随意选了几个布道点,并且把这几个布道点的情况公告给了郊区所有的居民,于是每个居民到离自己家最近的布道点去听课。
2.第一次听课之后,大家觉得距离太远了,于是每个牧师统计了一下自己的课上所有的居民的地址,搬到了所有地址的中心地带,并且在海报上更新了自己的布道点的位置。
3.牧师每一次移动不可能离所有人都更近,有的人发现A牧师移动以后自己还不如去B牧师处听课更近,于是每个居民又去了离自己最近的布道点…就这样,牧师每个礼拜更新自己的位置,居民根据自己的情况选择布道点,最终稳定了下来。

二、K-means算法步骤

  1. 先定义总共有多少个类/簇(cluster)
  2. 将每一个簇心(cluster centers)随机定在一个点上
  3. 将每个数据点关联到最近的簇中心所属的簇上
  4. 对于每一个簇找到其所有关联点的中心点(取每一个点坐标的平均值)
  5. 将上述点变为新的簇心
  6. 重复上述过程,直至每个簇所拥有的点不变

三、举个栗子
(一)若有A1~A6六个样本点,将其分为两个簇,其中A3,A4为两个簇的初始簇心,表格中的数据为样本点的X,Y坐标。

XY
A112
A214
A331
A435
A552
A654

(二)计算每个点到簇心的距离(采用距离公式计算),将距离近的点归为一类。

XYG1 distanceG2 distance
A112((3-1)**2+(1-2)**2)**0.5=2.243.61
A2143.612.24
A3310.004.00
A4354.000.00
A5522.243.61
A6543.612.24

对于A3作为簇心来说,A1,A3,A5距离最近,故将其归为一类;
对于A4作为簇心来说,A2,A4,A6距离最近,故将其归为一类.

(三)将第一类A1,A3,A5和第二类A2,A4,A6的X,Y值分别求平均,得到新的簇心。

XY
new M13.00(2+1+2)/3=1.67
new M23.004.43

(四)计算每个点到簇心的新距离,将距离近的点归为一类。

XYG1 distanceG2 distance
A112((3-1)**2+(1.67-2)**2)**0.5=2.033.07
A2143.072.03
A3310.673.33
A4353.330.67
A5522.033.07
A6543.072.03

对于M1作为簇心来说,A1,A3,A5距离最近,故将其归为一类;
对于M2作为簇心来说,A2,A4,A6距离最近,故将其归为一类.

(五)此时发现关联的点没有发生变化,所以之后的计算结果不会改变,停止计算。

(六)故,第一簇为A1,A3,A5,第二簇为A2,A4,A6.

四、算法特性

  1. 典型的无监督算法.why? 由于我们拿到的数据样本没有标签,需要通过算法执行来得到标签结果.
  2. K表示样本类别数,也是就在确定K值后,算法执行过后会分成K个簇.
  3. 距离的度量,常用欧几里得距离和余弦相似度计算 (先标准化)
  4. 优点:简单易实现,快速,适合常规数据集
  5. 缺点:K值难确定,复杂度与样本呈线性关系,很难发现任意形状的簇。

五、算法实现
1.导入第三方库

import random
from math import *
import matplotlib.pyplot as plt

2.读取文件数据

#从文件种读取数据
def read_data():
    data_points = [] # 初始化空的列表
    with open('data.txt','r') as fp:
        for line in fp:
            if line =='\n':
                continue
            data_points.append(tuple(map(float,line.split(' '))))#去掉空格,并将data中数据的类型转为tuple
        fp.close()
        return data_points

3.初始化聚类中心

#初始化聚类中心
def begin_cluster_center(data_points,k):
    center=[]
    length=len(data_points)#获取传入的数据长度
    rand_data = random.sample(range(0,length), k)#生成k个不同随机数 作为样本初始簇中心
    for i in range(k):#得出k个聚类中心(随机选出)
        center.append(data_points[rand_data[i]]) # 将初始样本簇中心追加到列表中
    return center

4.计算欧氏距离

#计算欧氏距离
def distance(a,b):
    length=len(a)
    sum = 0
    for i in range(length):
        sq = (a[i] - b[i]) ** 2 # 先平方
        sum += sq
    return sqrt(sum) # 开根号

5.分配样本,按照欧氏距离将所有的初始样本分配到k个聚类中心中的某一个

# 
def assign_points(data_points,center,k):
    assignment=[]
    for i in range(k):
        assignment.append([])
    for point in data_points:
        min = 10000000
        flag = -1
        for i in range(k):
            value=distance(point,center[i])#计算每个点到聚类中心的距离
            if value<min:
                min=value#记录距离的最小值
                flag=i   #记录此时聚类中心的下标
        assignment[flag].append(point)
    return assignment

6.更新聚类中心,计算每一簇中所有点的平均值

#更新聚类中心,计算每一簇中所有点的平均值
def update_cluster_center(center,assignment,k):
    for i in range(k):#assignment中的每一簇
        x=0
        y=0
        length=len(assignment[i])#每一簇的长度
        if length!=0:
            for j in range(length):  # 每一簇中的每个点
                x += assignment[i][j][0]  # 横坐标之和
                y += assignment[i][j][1]  # 纵坐标之和
            center[i] = (x / length, y / length)
    return center

7.计算平方误差

#计算平方误差
def getE(assignment,center):
    sum_E=0
    for i in range(len(assignment)):
        for j in range(len(assignment[i])):
            sum_E+=distance(assignment[i][j],center[i])
    return sum_E

8.计算各个聚类中心的新向量,更新距离,即每一类中每一维均值向量。
然后再进行分配,比较前后两个聚类中心向量是否相等,若不相等则进行循环,
否则终止循环,进入下一步。

def k_means(data_points,k):
    # 由于初始聚类中心是随机选择的,十分影响聚类的结果,聚类可能会出现有较大误差的现象
    # 因此如果由初始聚类中心第一次分配后有结果为空,重新选择初始聚类中心,重新再聚一遍,直到符合要求
    while 1:
        # 产生初始聚类中心
        begin_center = begin_cluster_center(data_points, k)
        # 第一次分配样本
        assignment = assign_points(data_points, begin_center, k)
        for i in range(k):
            if len(assignment[i]) == 0:#第一次分配之后有结果为空,说明聚类中心没选好,重新产生初始聚类中心
                continue
        break
    #第一次的平方误差
    begin_sum_E=getE(assignment,begin_center)
    # 更新聚类中心
    end_center = update_cluster_center(begin_center, assignment, k)
    # 第二次分配样本
    assignment = assign_points(data_points, end_center, k)
    # 第二次的平方误差
    end_sum_E = getE(assignment, end_center)
    count = 2  # 计数器
    #比较前后两个聚类中心向量是否相等
    #print(compare(end_center,begin_center)==False)
    while( begin_sum_E != end_sum_E):
        begin_center=end_center
        begin_sum_E=end_sum_E
        # 再次更新聚类中心
        end_center = update_cluster_center(begin_center, assignment, k)
        # 进行分配
        assignment = assign_points(data_points, end_center, k)
        #计算误差
        end_sum_E = getE(assignment, end_center)
        count = count + 1      #计数器加1
    return assignment,end_sum_E,end_center,count

9.打印计算结果

def print_result(count,end_sum_E,k,assignment):
    # 打印最终聚类结果
    print('经过', count, '次聚类,平方误差为:', end_sum_E)
    print('---------------------------------分类结果---------------------------------------')
    for i in range(k):
        print('第',i+1,'类数据:',assignment[i])
    print('--------------------------------------------------------------------------------\n')

10.可视化展示

def plot(k, assignment,center):
    #初始坐标列表
    x = []
    y = []
    for i in range(k):
        x.append([])
        y.append([])
    # 填充坐标 并绘制散点图
    for j in range(k):
        for i in range(len(assignment[j])):
            x[j].append(assignment[j][i][0])# 横坐标填充
        for i in range(len(assignment[j])):
            y[j].append(assignment[j][i][1])# 纵坐标填充
        plt.scatter(x[j], y[j],marker='o')
        plt.scatter(center[j][0], center[j][1],c='b',marker='*')#画聚类中心
    # 设置标题
    plt.title('K-means Scatter Diagram')
    # 设置X轴标签
    plt.xlabel('X')
    # 设置Y轴标签
    plt.ylabel('Y')
    # 显示散点图
    plt.show()
 
def main():
    # 4个聚类中心
    k = 4
    data_points =read_data()
    assignment, end_sum_E, end_center, count = k_means(data_points, k)
    min_sum_E = 1000
    #返回较小误差
    while min_sum_E>end_sum_E:
        min_sum_E=end_sum_E
        assignment, end_sum_E, end_center, count = k_means(data_points,k)
    print_result(count, min_sum_E, k, assignment)#输出结果
    plot(k, assignment,end_center)#画图
main()

在这里插入图片描述
在这里插入图片描述

相关文章:

  • JavaScript面向对象
  • 吐血总结 40道Python面试题集锦
  • Go 语言中的基本类型以及变量声明与初始化(Let‘s Go 三)
  • 前端基础01:HTML
  • java计算机毕业设计前台点菜系统源代码+数据库+系统+lw文档
  • QT QString编辑字符串-查询-类型转换操作
  • NFT重构票务系统
  • 国际电工委员会发布标准 IEC 62077:2022 《光纤互连设备和无源元件-光纤环行器-通用规范》
  • vue3.0--3.isRef、toRefs、toRef、readonly,公共数据配置、网络配置、app.use插件配置、路由配置
  • 【python】(十八)python常用第三方库——pymysql
  • 供应水溶性喹啉腈磺酸盐母体,QM-SO3,CAS:1800102-18-4
  • Unity Shader LOD详解
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • Linux环境:Nginx配置SSL证书,https协议请求 443端口
  • git tag相关
  • [case10]使用RSQL实现端到端的动态查询
  • 2017前端实习生面试总结
  • C语言笔记(第一章:C语言编程)
  • express.js的介绍及使用
  • go append函数以及写入
  • JavaWeb(学习笔记二)
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • ReactNative开发常用的三方模块
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • 百度小程序遇到的问题
  • 面试遇到的一些题
  • 正则表达式
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​secrets --- 生成管理密码的安全随机数​
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • "无招胜有招"nbsp;史上最全的互…
  • # Apache SeaTunnel 究竟是什么?
  • #laravel 通过手动安装依赖PHPExcel#
  • (1)SpringCloud 整合Python
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (译)2019年前端性能优化清单 — 下篇
  • (转)3D模板阴影原理
  • (转)http-server应用
  • (最全解法)输入一个整数,输出该数二进制表示中1的个数。
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • .gitignore文件---让git自动忽略指定文件
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .Net Winform开发笔记(一)
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .net中生成excel后调整宽度
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?
  • @Bean, @Component, @Configuration简析
  • [20170728]oracle保留字.txt