数据挖掘十大算法(二):K-Means、二分K-均值 python和sklearn实现

2023-11-18

早在刚接触数据挖掘算法时就已经看过,以及使用过简单的K-均值算法来做聚类,现在为了进一步的掌握该知识,通过机器学习实战又看了一遍,由于相对于其它算法较简单,所以看的也比较快,同时也学习了一下更为强大的二分K-均值算法,该算法建立在K-Means算法上,但难度不大,理论知识也很好理解,所以这里对两者的思路都记录一下。本篇文章主要内容(K-Means原理、二分K-Means原理、基础代码实现、sklearn实现)等。

K-Means原理:

    聚类是一种无监督的学习,它将相似的对象归到同一个簇中。有点像全自动分类,聚类方法几乎可以应用于所有对象,簇内的对象越相似,聚类的效果越好。K-均值(K-Means)属于聚类算法,之所以称为K-均值是因为它可以发现k个不同的簇,且每个簇的中心采用簇中所含值得均值计算而成。

实现聚类的思想:

  1. 随机选择K个中心值
  2. 根据样本数据各点与中心点的距离来进行归簇
  3. 通过整个簇的均值,重置每个簇的中心值
  4. 重复2、3,直至达到最大的迭代次数(例如:我这里的条件设置为本次与上次的平方误差相等)

看了这个步骤,感觉不会算法得人,都应该有了大概的思路。下面通过作者的代码来演示具体的操作:

代码:

样例数据(来自第十章):

from numpy import *
import matplotlib.pyplot as plt

# 加载本地数据
def loadDataSet(fileName):
    dataMat = []
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = list(map(float,curLine)) # 映射所有数据为浮点数
        dataMat.append(fltLine)
    return dataMat

# 欧式距离计算
def distEclud(vecA, vecB):
    return sqrt(sum(power(vecA - vecB, 2))) # 格式相同的两个向量做运算

# 中心点生成 随机生成最小到最大值之间的值
def randCent(dataSet, k):
    n = shape(dataSet)[1]
    centroids = mat(zeros((k,n))) # 创建中心点,由于需要与数据向量做运算,所以每个中心点与数据得格式应该一致(特征列)
    for j in range(n):  # 循环所有特征列,获得每个中心点该列的随机值
        minJ = min(dataSet[:,j])
        rangeJ = float(max(dataSet[:,j]) - minJ)
        centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1)) # 获得每列的随机值 一列一列生成
    return centroids

# 返回 中心点矩阵和聚类信息
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m,2))) # 创建一个矩阵用于记录该样本 (所属中心点 与该点距离)
    centroids = createCent(dataSet, k)
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False  # 如果没有点更新则为退出
        for i in range(m):
            minDist = inf; minIndex = -1
            for j in range(k):  # 每个样本点需要与 所有 的中心点作比较
                distJI = distMeas(centroids[j,:],dataSet[i,:])  # 距离计算
                if distJI < minDist:
                    minDist = distJI; minIndex = j
            if clusterAssment[i,0] != minIndex: # 若记录矩阵的i样本的所属中心点更新,则为True,while下次继续循环更新
                clusterChanged = True
            clusterAssment[i,:] = minIndex,minDist**2   # 记录该点的两个信息
        # print(centroids)
        for cent in range(k): # 重新计算中心点
            # print(dataSet[nonzero(clusterAssment[:,0] == cent)[0]]) # nonzero返回True样本的下标
            ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]] # 得到属于该中心点的所有样本数据
            centroids[cent,:] = mean(ptsInClust, axis=0) # 求每列的均值替换原来的中心点
    return centroids, clusterAssment

datMat = mat(loadDataSet('testSet.txt'))
myCentroids,clustAssing = kMeans(datMat,4)
print(myCentroids)
print(clustAssing)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(myCentroids[:,0].flatten().A[0],myCentroids[:,1].flatten().A[0],color='r',s=60)
ax.scatter(datMat[:,0].flatten().A[0],datMat[:,1].flatten().A[0])
plt.show()

中心点:

每个点的所属簇、及平方和误差:

K-Means算法很简单,实现起来也不困难,这是它的优势,但有时你可能会发现K-均值收敛,但聚类效果并不是很好,这是因为K-均值收敛到了局部最小值,而非全局最小值(局部最小值表示结果还可以,但还可以更好,全局最小值表示结果可能是最好的了)。

由此我们需要使用后处理来提高聚类性能,一种度量聚类效果的指标是SSE(误差平方和),就是上面clusterAssment的第一列之和。SSE越小表示越接近质心点,由于取了平方,所以更重视距离远的点。增加簇可以减少SSE,但这可能不符合要求,另一种方法是将具有较大SSE的簇进行二分,具体实现时可以将最大簇包含的点过滤出来并在这些点上运用K-均值算法,K设为2。

基于划分簇的思想下面介绍二分K-均值

二分K-均值:

    首先将所有点作为一个簇,然后将该簇一分为二。之后选择一个簇继续进行划分,选择哪一个簇进行划分取决于对其划分是否可以最大程度降低SSE的值。而划分就是上面提到的K-均值的思想了,利用上面的函数k设为2来划分。通过不断重复的操作,直到达到需要的簇数量。

代码:

样例数据:

# 二分均值聚类    SSE误差平方和    nonzero判断非0或给定条件,返回两个数组,[0]为True的下标组
def biKmeans(dataSet, k, distMeas=distEclud):
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m,2)))  # 保存数据点的信息(所属类、误差)
    centroid0 = mean(dataSet, axis=0).tolist()[0]   # 根据数据集均值获得第一个簇中心点
    centList =[centroid0] # 创建一个带有质心的 [列表],因为后面还会添加至k个质心
    for j in range(m):
        clusterAssment[j,1] = distMeas(mat(centroid0), dataSet[j,:])**2     # 求得dataSet点与质心点的SSE
    while (len(centList) < k):
        lowestSSE = inf
        for i in range(len(centList)):
            ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:] # 与上面kmeans一样获得属于该质心点的所有样本数据
            # 二分类
            centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)  # 返回中心点信息、该数据集聚类信息
            sseSplit = sum(splitClustAss[:,1])  # 这是划分数据的SSE    加上未划分的 作为本次划分的总误差
            sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])   # 这是未划分的数据集的SSE
            print("划分SSE, and 未划分SSE: ",sseSplit,sseNotSplit)
            if (sseSplit + sseNotSplit) < lowestSSE:    # 将划分与未划分的SSE求和与最小SSE相比较 确定是否划分
                bestCentToSplit = i         # 得出当前最适合做划分的中心点
                bestNewCents = centroidMat  # 划分后的两个新中心点
                bestClustAss = splitClustAss.copy() # 划分点的聚类信息
                lowestSSE = sseSplit + sseNotSplit
        bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList)   # 由于是二分,所有只有0,1两个簇编号,将属于1的所属信息转为下一个中心点
        bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit # 将属于0的所属信息替换用来聚类的中心点
        print('本次最适合划分的质心点: ',bestCentToSplit)
        print('被划分数据数量: ', len(bestClustAss))
        centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0] # 与上面两条替换信息相类似,这里是替换中心点信息,上面是替换数据点所属信息
        centList.append(bestNewCents[1,:].tolist()[0])
        clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:] = bestClustAss # 替换部分用来聚类的数据的所属中心点与误差平方和 为新的数据
    return mat(centList), clusterAssment

datMat3 = mat(loadDataSet('testSet2.txt'))
centList,myNewAssments = biKmeans(datMat3,3)
print(centList)
print(myNewAssments)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(centList[:,0].flatten().A[0],centList[:,1].flatten().A[0],color='r',s=60)
ax.scatter(datMat3[:,0].flatten().A[0],datMat3[:,1].flatten().A[0])
plt.show()

中心值:

每个点的所属簇、及SSE值:

大部分的解释都在代码上,这里就不再累述了。二分K-均值相比于K-均值效果更好,克服了K-Means算法收敛于局部最小值得问题。

sklearn实现:

由于篇幅问题,这里简单说一下。通过sklearn的cluster可以使用KMeans算法,或者使用另一种方法Mini Batch K-Means。

Mini Batch K-Means算法是K-Means算法的变种,采用小批量的数据子集减小计算时间,同时仍试图优化目标函数,这里所谓的小批量是指每次训练算法时所随机抽取的数据子集,采用这些随机产生的子集进行训练算法,大大减小了计算时间,与其他算法相比,减少了k-均值的收敛时间,小批量k-均值产生的结果,一般只略差于标准算法。

官方文档的连接:http://scikit-learn.org/stable/modules/clustering.html#mini-batch-kmeans

可以参考的博客:

https://blog.csdn.net/sinat_26917383/article/details/70240628    参数含义

https://blog.csdn.net/gamer_gyt/article/details/51244850

 

当然如果可以的话,最好使用官方的文档进行深入的学习。

参考书籍:《机器学习实战》

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据挖掘十大算法(二):K-Means、二分K-均值 python和sklearn实现 的相关文章

  • ES 版本,及重要特性

    参考 https www cnblogs com flyrock ES release 地址 https www elastic co cn downloads past releases elasticsearch ES版本 发布日期 版

随机推荐

  • 熊啸锋:精准营销及推广的四个步骤,倍增你的利润

    哈喽 我是熊啸锋老师 今天分享的主题是精准营销及推广的四个步骤 作为营销人 企业老板 项目负责人 市场开发人员等 你会经常面临 如何开发客户 如何获得大量的潜在客户名单 等很多的问题 还经常有人抱怨说 我们获取的潜在客户名单不精准 成交率非
  • Linux中清空文件的方法

    Linux中清空文件的方法 平时工作过程中 经常会遇到需要清空linux中某个日志文件的方法 下面总结一下几个常用的方法 以下待清空的文件名统一使用 test txt 表示 方法1 vi 中使用 d 1 输入 vi test txt 回车
  • word添加gif

    word添加gif动图最简单的方法 无需链接无需插件 X to Y的博客 CSDN博客 word插入动图 原文链接 https blog csdn net X To Y article details 124415532 文章目录 word
  • c++ Graphics 实现俄罗斯方块

    俄罗斯方块 一 游戏规则 1 方块种类 2 操作规则 玩家可以通过 按键 功能 a 向左一格 d 向右一格 s 顺时针旋转90度 w 逆时针旋转90度 3 积分规则 玩家根据消除的行列数量获取得分 数量 得分 1行 10分 2行 30分 3
  • Vue中的import中@的作用

    这是webpack的路径别名 相关代码定义在配置文件webpack base config里 resolve 自动补全的扩展名 extensions js vue json 默认路径代理 例如 import Vue from vue 会自动
  • UVA-10603 倒水问题 题解答案代码 算法竞赛入门经典第二版

    GitHub jzplp aoapc UVA Answer 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 使用广度优先搜索和优先队列 如果找到最小的点则退出 找不到就遍历所有的情况 include
  • 在vue中引入高德地图

    既然要用到高德地图首先要申请成为高德地图开发者 并申请使用高德地图的key这两点在这篇文章就不过多赘述 有需要的小伙伴可以查查资料 或者去高德地图api官网都有很详细的介绍 高德地图官网 简单提一下申请秘钥流程 web端 控制台 gt 应用
  • Android中的关于MDM中的几个方法举例

    首先介绍一下MDM是什么的缩写 MDM是什么 MDM 是 Mobile Device Management 的缩写 中文翻译过来就是移动设备管理 随着移动设备计算能力地增强 移动设备携带越来越方便 移动化办公已经成为一种潮流 一种趋势 企业
  • MATLAB_第二篇神经网络学习_BP神经网络

    非常感谢博主wishes61的分享 这篇博客只是为了记录下第一个神经网络的训练 BP神经网络代码实现 1 BP神经网络的简介和结构参数 1 1 BP神经网络的结构组成 1 2 神经元结构示意图 1 3 BP神经网络训练界面的参数解读 2 B
  • 【华为OD机试】战场索敌(C++ Python Java)2023 B卷

    时间限制 C C 1秒 其他语言 2秒 空间限制 C C 262144K 其他语言524288K 64bit IO Format lld 题目描述 有一个大小是N M的战场地图 被墙壁 分隔成大小不同的区域 上下左右四个方向相邻的空地 属于
  • 蓝牙协议规范--L2CAP

    L2CAP 分析 记住一点 软件和硬件分开理解 数据经由物理通道交互 上层通道由各层协议打通 L2CAP 全称为逻辑链路控制与适配协议 Logical Link Control and Adaptation Protocol 位于基带层之上
  • 聚簇索引与非聚簇索引(也叫二级索引)

    索引 索引 是 存储引擎 用于快速找到记录的一种 数据结构 MYSQL中索引在存储引擎层实现 而非服务器层 索引类型 聚簇索引 非聚簇索引 二级索引 主键索引 辅助索引 复合索引 前缀索引 唯一索引 压缩索引 全文索引 Hash索引 列索引
  • Redis学习笔记2:了解 Redis 入门

    1 Redis是什么 Remote Dictionary Server 远程字典服务 Redis是现在最受欢迎的NoSQL数据库之一 Redis是一个使用ANSI C编写的开源 包含多种数据结构 支持网络 基于内存 可选持久性的键值对存储数
  • 如何的pycharm远程连接服务器Ftp

    话不多说 我们直接开始上图操作 以上就是整体的配置过程
  • ElasticSearch入门

    文章目录 一 ElasticSearch简介 1 什么是ElasticSearch 2 ElasticSearch使用案例 3 ElasticSearch对 Solr 二 ElasticSearch相关概念 术语 1 概述 2 索引 ind
  • MyBatis学习(二):解析MyBatis配置文件的写法和使用原理

    MyBatis学习 一 一个简单的演示 上面就是一个很简单的MyBatis的应用实例 可以看看 对于如何如此做可能就不是很清楚了 首先每一个MyBatis的应用程序都是以一个SqlSessionFactory对象的实例为核心 SqlSess
  • excel在双显示器上打开两个独立的xlsx表格

    平时配置的双显示器 要在两个显示器上各打开一个excel表格 一个用来做参考 另一个用来制作新表格 默认的office竟然不支持同时开两个独立窗口的excel表格 解决方式是安装微软的新补丁 http download microsoft
  • boa(web服务器)之交叉编译、移植、cgi、文件上传篇

    boa简介 BOA 服务器是一个小巧高效的web服务器 是一个运行于unix或linux下的 支持CGI的 适合于嵌入式系统的单任务的http服务器 源代码开放 性能高 由于它是一个单任务的Web服务器 只能一次完成用户的请求 而不会for
  • JS 读写文件(实例)

    http blog sina com cn s blog 62cd41130100l7c5 html 用js不能直接读取文件 但是可以利用浏览器提供的activex来实现读写文件的方法 只在IE下测试过 其他浏览器下的activex对象不太
  • 数据挖掘十大算法(二):K-Means、二分K-均值 python和sklearn实现

    早在刚接触数据挖掘算法时就已经看过 以及使用过简单的K 均值算法来做聚类 现在为了进一步的掌握该知识 通过机器学习实战又看了一遍 由于相对于其它算法较简单 所以看的也比较快 同时也学习了一下更为强大的二分K 均值算法 该算法建立在K Mea