Bisecting k-means聚类算法,即二分k均值算法,它是k-means聚类算法的一个变体,主要是为了改进k-means算法随机选择初始质心的随机性造成聚类结果不确定性的问题,而Bisecting

k-means算法受随机选择初始质心的影响比较小。

首先,我们考虑在欧几里德空间中,衡量簇的质量通常使用如下度量:误差平方和(Sum

of the Squared Error,简称SSE),也就是要计算执行聚类分析后,对每个点都要计算一个误差值,即非质心点到最近的质心的距离。那么,既然每个非质心点都已经属于某个簇,也就是要计算每个非质心点到其所在簇的质心的距离,最后将这些距离值相加求和,作为SSE去评估一个聚类的质量如何。我们的最终目标是,使得最终的SSE能够最小,也就是一个最小化目标SSE的问题。在n维欧几里德空间,SSE形式化地定义,计算公式如下:

Bisecting k-means聚类算法的基本思想是,通过引入局部二分试验,每次试验都通过二分具有最大SSE值的一个簇,二分这个簇以后得到的2个子簇,选择2个子簇的总SSE最小的划分方法,这样能够保证每次二分得到的2个簇是比较优的(也可能是最优的),也就是这2个簇的划分可能是局部最优的,取决于试验的次数。

Bisecting k-means聚类算法的具体执行过程,描述如下所示:

1、初始时,将待聚类数据集D作为一个簇C0,即C={C0},输入参数为:二分试验次数m、k-means聚类的基本参数;

2、取C中具有最大SSE的簇Cp,进行二分试验m次:调用k-means聚类算法,取k=2,将Cp分为2个簇:Ci1、Ci2,一共得到m个二分结果集合B={B1,B2,…,Bm},其中,Bi={Ci1,Ci2},这里Ci1和Ci2为每一次二分试验得到的2个簇;

3、计算上一步二分结果集合B中,每一个划分方法得到的2个簇的总SSE值,选择具有最小总SSE的二分方法得到的结果:Bj={Cj1,Cj2},并将簇Cj1、Cj2加入到集合C,并将Cp从C中移除;

4、重复步骤2和3,直到得到k个簇,即集合C中有k个簇。

聚类算法实现

基于上面描述的聚类执行过程,使用Java实现Bisecting k-means聚类,代码如下所示:

@Override

public void clustering() {

// parse sample files

final List allPoints = Lists.newArrayList();

FileUtils.read2DPointsFromFiles(allPoints, "[\t,;\\s]+", inputFiles);

// 从文件中读取二维坐标点,加入到集合allPoints中

final int bisectingK = 2;

int bisectingIterations = 0;

int maxInterations = 20;

List points = allPoints;

final Map

Set>> clusteringPoints = Maps.newConcurrentMap();

// 最终的聚类结果集合

while(clusteringPoints.size() <= k) { // 当得到k个簇,则算法终止

LOG.info("Start bisecting iterations: #" + (++bisectingIterations) + ",

bisectingK=" + bisectingK + ",maxMovingPointRate=" + maxMovingPointRate +

", maxInterations=" + maxInterations + ", parallism=" + parallism);

// for k=bisectingK, execute k-means clustering

// bisecting trials

KMeansClustering bestBisectingKmeans = null;

double minTotalSSE = Double.MAX_VALUE;

for (int i = 0; i < m; i++) {

// 执行二分试验:调用k-means聚类算法,将输入的点集进行二分,得到2个簇,试验执行m次

final KMeansClustering kmeans = new KMeansClustering(bisectingK, maxMovingPointRate,

maxInterations, parallism);

kmeans.initialize(points);

// the clustering result should have 2 clusters

kmeans.clustering();

double currentTotalSSE = computeTotalSSE(kmeans.getCenterPointSet(),

kmeans.getClusteringResult()); // 计算一次二分试验中总的SSE的值

if(bestBisectingKmeans == null) {

bestBisectingKmeans = kmeans;

minTotalSSE = currentTotalSSE;

} else {

if(currentTotalSSE < minTotalSSE) {

// 记录总SSE最小的二分聚类,通过kmeans保存二分结果

bestBisectingKmeans = kmeans;

minTotalSSE = currentTotalSSE;

}

}

LOG.info("Bisecting trial <> : minTotalSSE=" + minTotalSSE + ",

currentTotalSSE=" + currentTotalSSE);

}

LOG.info("Best biscting: minTotalSSE=" + minTotalSSE);

// merge cluster points for choosing cluster bisected again

int id = generateNewClusterId(clusteringPoints.keySet());

// 每次执行k-means聚类,都多了一个簇,为多出的这个簇分配一个编号

Set bisectedCentroids = bestBisectingKmeans.getCenterPointSet();

// 二分得到的2个簇的质心的集合

merge(clusteringPoints, id, bisectedCentroids,

bestBisectingKmeans.getClusteringResult().getClusteredPoints());

// 将二分得到的2个簇的集合,合并加入到最终结果的集合中

if(clusteringPoints.size() == k) { // 已经得到k个簇,算法终止

break;

}

// compute cluster to be bisected

ClusterInfo cluster = chooseClusterToBisect(clusteringPoints);

// remove centroid from collected clusters map

clusteringPoints.remove(cluster.centroidToBisect);

LOG.info("Cluster to be bisected: " + cluster);

points = Lists.newArrayList();

for(ClusterPoint cp : cluster.clusterPointsToBisect) {

points.add(cp.getPoint());

}

LOG.info("Finish bisecting iterations: #" + bisectingIterations + ",

clusterSize=" + clusteringPoints.size());

}

// finally transform to result format

Iterator

Set>>> iter = clusteringPoints.entrySet().iterator();

while(iter.hasNext()) { // 构造最终输出结果的数据结构

Entry>> entry = iter.next();

clusteredPoints.put(entry.getKey().getId(), entry.getValue());

centroidSet.add(entry.getKey());

}

}

上面,我们调用chooseClusterToBisect方法区实现对具有最大的SSE的簇进行二分,具体选择的实现过程,代码如下所示:

private ClusterInfo chooseClusterToBisect(Map

Set>> clusteringPoints) {

double maxSSE = 0.0;

int clusterIdWithMaxSSE = -1;

CenterPoint centroidToBisect = null;

Set> clusterToBisect = null;

Iterator

Set>>> iter = clusteringPoints.entrySet().iterator();

while(iter.hasNext()) {

Entry>> entry = iter.next();

CenterPoint centroid = entry.getKey();

Set> cpSet = entry.getValue();

double sse = computeSSE(centroid, cpSet); // 计算一个簇的SSE值

if(sse > maxSSE) {

maxSSE = sse;

clusterIdWithMaxSSE = centroid.getId();

centroidToBisect = centroid;

clusterToBisect = cpSet;

}

}

return new ClusterInfo(clusterIdWithMaxSSE, centroidToBisect, clusterToBisect, maxSSE);

// 将待分裂的簇的信息保存在ClusterInfo对象中

}

private double computeSSE(CenterPoint centroid,

Set> cpSet)

{

// 计算某个簇的SSE

double sse = 0.0;

for(ClusterPoint cp : cpSet) {

// update cluster id for ClusterPoint object

cp.setClusterId(centroid.getId());

double distance = MetricUtils.euclideanDistance(cp.getPoint(),

centroid);

sse += distance * distance;

}

return sse;

}

在二分试验过程中,因为每次二分都生成2个新的簇,通过计算这2个簇的总SSE的值,通过迭代计算,找到一个局部最小的总SSE对应的2个簇的划分方法,然后将聚类生成的2簇加入到最终的簇集合中,总SSE的计算法方法在computeTotalSSE方法中,如下所示:

聚类效果对比

下面,我们对比一下,k-means算法与Bisecting k-means多次运行的聚类结果对比,如下图所示:

private double computeTotalSSE(Set centroids, ClusteringResult clusteringResult) {

double sse = 0.0;

for(CenterPoint center : centroids) { // 计算2个簇的总SSE值

int clusterId = center.getId();

for(ClusterPoint p : clusteringResult.getClusteredPoints().get(clusterId)) {

double distance = MetricUtils.euclideanDistance(p.getPoint(), center);

sse += distance * distance;

}

}

return sse;

}

上图中,第一排是执行k-means聚类得到的效果图,第二排是执行Bisecting k-means聚类得到的效果图,其中编号为9999的点为质心点。第二排效果图看似多次计算质心没有变化,但是实际是变化的,只是质心点的位置比较稳定,例如,下面是两组质心点:

462.9642857142857,303.5,7

172.0,279.625,8

236.54285714285714,136.25714285714287,10

105.125,65.9375,11

75.91304347826087,185.7826086956522,12

56.03333333333333,299.53333333333336,13

273.5,117.5,14

415.5952380952381,68.71428571428571,15

329.04,308.68,16

374.35,200.55,17

172.0,279.625,5

462.9642857142857,303.5,8

105.125,65.9375,9

236.54285714285714,136.25714285714287,10

273.6666666666667,124.44444444444444,11

415.5952380952381,68.71428571428571,12

75.91304347826087,185.7826086956522,13

56.03333333333333,299.53333333333336,14

379.57894736842104,201.6315789473684,15

329.04,308.68,16

同k-means算法一样,Bisecting k-means算法不适用于非球形簇的聚类,而且不同尺寸和密度的类型的簇,也不太适合。

kmeans python interation flag_Bisecting k-means聚类算法实现相关推荐

  1. k means聚类算法_一文读懂K-means聚类算法

    1.引言 什么是聚类?我们通常说,机器学习任务可以分为两类,一类是监督学习,一类是无监督学习.监督学习:训练集有明确标签,监督学习就是寻找问题(又称输入.特征.自变量)与标签(又称输出.目标.因变量) ...

  2. k means聚类算法_K-Means 聚类算法 20210108

    说到聚类,应先理解聚类和分类的区别 聚类和分类最大的不同在于:分类的目标是事先已知的,而聚类则不一样,聚类事先不知道目标变量是什么,类别没有像分类那样被预先定义出来. K-Means 聚类算法有很多种 ...

  3. OpenCV官方文档 理解k - means聚类

    理解k - means聚类 目标 在这一章中,我们将了解k - means聚类的概念,它是如何工作等. 理论 我们将这个处理是常用的一个例子. t恤尺寸问题 考虑一个公司要发布一个新模型的t恤. 显然 ...

  4. k均值聚类算法python_K均值和其他聚类算法:Python快速入门

    k均值聚类算法python This post was originally published here 这篇文章最初发表在这里 Clustering is the grouping of obje ...

  5. k均值聚类算法(K Means)及其实战案例

    算法说明 K均值聚类算法其实就是根据距离来看属性,近朱者赤近墨者黑.其中K表示要聚类的数量,就是说样本要被划分成几个类别.而均值则是因为需要求得每个类别的中心点,比如一维样本的中心点一般就是求这些样本 ...

  6. K-Means(K均值聚类算法)

    K-Means(K均值聚类算法) 1.前言 要学习聚类算法就要知道聚类学习算法是什么,为什么要学习聚类学习聚类学习算法,有什么用途,下面就简单的做一下介绍,并且详细的说明k-means均值聚类学习算法 ...

  7. python(scikit-learn)实现k均值聚类算法

    k均值聚类算法原理详解 示例为链接中的例题 直接调用python机器学习的库scikit-learn中k均值算法的相关方法 from sklearn.cluster import KMeans imp ...

  8. K均值聚类算法(Kmeans)讲解及源码实现

    K均值聚类算法(Kmeans)讲解及源码实现 算法核心 K均值聚类的核心目标是将给定的数据集划分成K个簇,并给出每个数据对应的簇中心点.算法的具体步骤描述如下. 数据预处理,如归一化.离群点处理等. ...

  9. 机器学习实战-61:K均值聚类算法(K-Means)

    K均值聚类算法(K-Means) 深度学习原理与实践(开源图书)-总目录,建议收藏,告别碎片阅读! 机器学习分为监督学习.无监督学习和半监督学习(强化学习).无监督学习最常应用的场景是聚类(clust ...

最新文章

  1. php memcached 扩展安装目录,php安装memcached扩展
  2. 是什么造成了网管员的低工资?
  3. mybatis中的智能标签之二
  4. JSF的工作方式和调试方式–可以使用polyglot吗?
  5. 使用Thumbnailator压缩照片
  6. [渝粤教育] 西南科技大学 货币银行学 在线考试复习资料(1)
  7. Python网络编程(http协议,IO多路复用、select内核监听)
  8. 罗技 连点 脚本_罗技 G502 无线版体验:告别了线材,而且变得更轻了
  9. 在Yalmip中应用SDPT3
  10. 语音转写和语音听写_如何在Windows 10上使用语音听写
  11. win10输入法变成繁体字如何解决
  12. 无法创建新虚拟机 无法打开配置文件 拒绝访问
  13. 移动视频客户端详细对比
  14. 成都Uber优步司机奖励政策(3月4日)
  15. GraphQL基金会宣布与联合开发基金会合作推动开源和开放标准
  16. 【安信可首款4G模组CA-01直连阿里物联网平台①】产品创建
  17. 【新知实验室】TRTC体验
  18. 福大软工1816 · 团队现场编程实战(抽奖系统
  19. 免费获得Java 7并发食谱
  20. Java SSM外卖跑腿系统

热门文章

  1. android坐标画图软件下载,地图坐标app下载-地图坐标软件下载v4.8.15 安卓版-西西软件下载...
  2. python一只青蛙一次可以_Python面试题系列之11 变态青蛙跳
  3. ion orphaned memory
  4. 如何打开usb计算机连接网络设置,usb共享网络怎么用
  5. 医院pacs系统服务器配置,浪潮为千佛山医院PACS系统开“药方”
  6. linux降调软件下载,o的发音有几种
  7. Python常见web框架汇总
  8. 2020哔哩哔哩校招后端开发笔试编程题总结
  9. 编写应用程序,计算两个非零正整数的最大公约数和最小公倍数,要求两个非零正整数从键盘输入。
  10. Transformer架构:位置编码