K-means聚类是一种非常流行的聚类算法,它的目标是将n个样本划分到k个簇中,使得每个样本属于与其最近的均值(即簇中心)对应的簇,从而使得簇内的方差最小化。K-means聚类算法简单、易于实现,并且在许多应用中都非常有效。


K-means算法的基本步骤:

  • 选择初始中心:随机选择k个样本点作为初始的簇中心,或者使用K-means++算法来更智能地选择初始簇中心。
  • 分配样本:将每个样本点分配到最近的簇中心,形成k个簇。
  • 更新簇中心:重新计算每个簇的中心,通常是簇内所有点的均值。
  • 迭代优化:重复步骤2和3,直到簇中心不再发生显著变化,或者达到预设的迭代次数。
  • 终止条件:当簇中心在连续迭代中的变化小于某个阈值,或者达到预设的最大迭代次数时,算法终止。

K-means算法的数学表示:

设 C={c1,c2,...,ck}C={c1,c2,...,ck} 为簇中心的集合,X={x1,x2,...,xn}X={x1,x2,...,xn} 为样本点集合。

K-means的目标是最小化簇内误差平方和(Within-Cluster Sum of Squares, WCSS):

J(C)=∑i=1k∑x∈Si∣∣x−ci∣∣2J(C)=∑i=1k∑x∈Si∣∣x−ci∣∣2

其中,SiSi 是簇 cici 中的样本点集合。

K-means算法的优缺点:

优点:

  • 算法简单,易于理解和实现。
  • 在处理大数据集时,计算效率较高。
  • 可以用于发现任意形状的簇。

缺点:

  • 需要预先指定k值,而k值的选择可能依赖于领域知识或试错。
  • 对初始簇中心的选择敏感,可能导致局部最优解。
  • 对噪声和异常点敏感,可能影响簇中心的计算。
  • 只能发现数值型特征的簇,不适合文本数据等非数值型数据。

K-means++算法:

K-means++是一种改进的K-means算法,用于更智能地选择初始簇中心,从而提高聚类的质量。K-means++的基本思想是:

  • 随机选择一个点作为第一个簇中心。
  • 对于每个剩余的点,计算其到最近簇中心的距离,并根据距离的平方选择下一个簇中心。
  • 重复步骤2,直到选择k个簇中心。

实际应用:

K-means聚类可以应用于多种场景,包括但不限于:

  • 市场细分:根据客户的特征将客户分组。
  • 图像分割:将图像分割成不同的区域或对象。
  • 社交网络分析:发现社交网络中的社区结构。
  • 文本聚类:对文档或新闻文章进行分组。

K-means聚类是一种非常实用的工具,但需要根据具体问题和数据集的特性来调整和优化。

下面是一个简单的Java实现K-means聚类算法的示例代码。这个示例将演示如何使用K-means算法对一组二维点进行聚类。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random; public class KMeansClustering { static class Point {
double x, y; Point(double x, double y) {
this.x = x;
this.y = y;
} @Override
public String toString() {
return String.format("(%f, %f)", x, y);
}
} public static void kMeans(List<Point> points, int k, int maxIterations) {
Random rand = new Random();
List<Point> centroids = new ArrayList<>();
// 初始化质心
for (int i = 0; i < k; i++) {
centroids.add(points.get(rand.nextInt(points.size())));
} for (int iter = 0; iter < maxIterations; iter++) {
// 1. 将每个点分配到最近的质心
List<List<Point>> clusters = new ArrayList<>();
for (int i = 0; i < k; i++) {
clusters.add(new ArrayList<>());
}
for (Point point : points) {
double minDistance = Double.MAX_VALUE;
int closestCentroid = 0;
for (int j = 0; j < k; j++) {
double dist = point.distance(centroids.get(j));
if (dist < minDistance) {
minDistance = dist;
closestCentroid = j;
}
}
clusters.get(closestCentroid).add(point);
} // 2. 更新质心
boolean changed = false;
List<Point> newCentroids = new ArrayList<>();
for (List<Point> cluster : clusters) {
if (cluster.isEmpty()) {
newCentroids.add(centroids.get(0)); // 如果某个簇为空,随机选择一个质心
changed = true;
} else {
Point newCentroid = cluster.get(0);
for (Point point : cluster) {
newCentroid = new Point(
newCentroid.x / cluster.size() + point.x / cluster.size(),
newCentroid.y / cluster.size() + point.y / cluster.size()
);
}
newCentroids.add(newCentroid);
}
} // 检查质心是否变化,如果没有则停止迭代
if (!changed && centroids.equals(newCentroids)) {
break;
} centroids.clear();
centroids.addAll(newCentroids);
} // 输出最终的质心和簇
for (int i = 0; i < centroids.size(); i++) {
System.out.println("Centroid " + i + ": " + centroids.get(i));
System.out.print("Cluster " + i + ": ");
for (Point point : clusters.get(i)) {
System.out.print(point + " ");
}
System.out.println();
}
} public static void main(String[] args) {
List<Point> points = new ArrayList<>();
points.add(new Point(1.0, 2.0));
points.add(new Point(1.5, 1.8));
points.add(new Point(5.0, 8.0));
points.add(new Point(8.0, 8.0));
points.add(new Point(1.0, 0.6));
points.add(new Point(9.0, 11.0));
points.add(new Point(8.0, 2.0));
points.add(new Point(10.0, 2.0));
points.add(new Point(9.0, 3.0)); int k = 3; // 簇的数量
int maxIterations = 100; // 最大迭代次数 kMeans(points, k, maxIterations);
}
}

解释说明:

  • Point类:一个简单的Point类,包含x和y坐标,并重写了toString方法以便于打印。

  • kMeans方法:

    分配点到最近的质心:对于每个点,计算其到每个质心的距离,并将点分配到最近的质心所代表的簇。

    更新质心:计算每个簇所有点的均值,作为新的质心。

    接受一组点、簇的数量k和最大迭代次数maxIterations作为参数。

    随机选择初始质心。

    进行迭代,每次迭代包括两个主要步骤:

    • 分配点到最近的质心:对于每个点,计算其到每个质心的距离,并将点分配到最近的质心所代表的簇。
    • 更新质心:计算每个簇所有点的均值,作为新的质心。
  • 分配点到最近的质心:对于每个点,计算其到每个质心的距离,并将点分配到最近的质心所代表的簇。

  • 更新质心:计算每个簇所有点的均值,作为新的质心。

  • 如果质心没有变化,或者达到最大迭代次数,则停止迭代。

main方法:创建了一个点的列表,并指定了簇的数量和最大迭代次数,然后调用kMeans方法进行聚类。

这个示例代码演示了K-means聚类的基本实现,但它没有使用K-means++算法来选择初始质心,也没有处理空簇的情况。在实际应用中,可能需要根据具体问题进行相应的优化和改进。

K-means聚类是一种非常流行的聚类算法的更多相关文章

  1. 软件——机器学习与Python,聚类,K——means

    K-means是一种聚类算法: 这里运用k-means进行31个城市的分类 城市的数据保存在city.txt文件中,内容如下: BJ,2959.19,730.79,749.41,513.34,467. ...

  2. DBSCAN聚类︱scikit-learn中一种基于密度的聚类方式

    一.DBSCAN聚类概述 基于密度的方法的特点是不依赖于距离,而是依赖于密度,从而克服基于距离的算法只能发现"球形"聚簇的缺点. DBSCAN的核心思想是从某个核心点出发,不断向密 ...

  3. PolyCluster: Minimum Fragment Disagreement Clustering for Polyploid Phasing 多聚类:用于多倍体的最小碎片不一致聚类

    摘要 分型是计算生物学的一个新兴领域,在临床决策和生物医学科学中有着重要的应用. 虽然机器学习技术在许多生物医学应用中显示出巨大的潜力,但它们在分型中的用途尚未完全理解. 在本文中,我们研究了基于聚类 ...

  4. murmurhash2算法 和 DJB Hash算法是目前最流行的hash算法

    murmurhash2算法 和 DJB Hash算法是目前最流行的hash算法 1.DJB HASH算法 1 2 3 4 5 6 7 8 9 10 11 /* the famous DJB Hash ...

  5. 一种局部二值化算法:Sauvola算法

    之前接触过全局二值化(OTSU算法),还有OPENCV提供的自适应二值化,最近又了解到一种新的局部二值化算法,Sauvola算法. 转载自:http://www.dididongdong.com/ar ...

  6. C/C++中几种经典的垃圾回收算法

    1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...

  7. 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列。对于1<=i,j<=k,求k个最小的(ai+bj)。要求算法尽量高效。

    有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列.对于1<=i,j<=k,求k个最小的(ai+bj).要求算法尽量高效. int * ...

  8. C++ 几种经典的垃圾回收算法

    之前遇到了一篇好文(https://blog.csdn.net/wallwind/article/details/6889917)准备学习一下的,课程繁忙就忘记了,今日得闲,特来补一下. 自己写一遍加 ...

  9. Self Organizing Maps (SOM): 一种基于神经网络的聚类算法

    自组织映射神经网络, 即Self Organizing Maps (SOM), 可以对数据进行无监督学习聚类.它的思想很简单,本质上是一种只有输入层--隐藏层的神经网络.隐藏层中的一个节点代表一个需要 ...

  10. [转]Javascript中几种较为流行的继承方式

    出处:http://www.jianshu.com/p/a6c005228a75 开篇 从'严格'意义上说,javascript并不是一门真正的面向对象语言.这种说法原因一般都是觉得javascrip ...

随机推荐

  1. WPF 使用 Win10 的 WinRT 自带 Windows.Media.Ocr 实现图片转文本

    世界上有很多 OCR 识别技术,本文来和大家介绍如果在 WPF 里,在运行到 win10 的设备上,通过 Windows Runtime 自带的 Windows.Media.Ocr 实现在给定的图片里 ...

  2. WPF 简单聊聊如何使用 DrawGlyphRun 绘制文本

    在 WPF 里面,提供的使用底层的方法绘制文本是通过 DrawGlyphRun 的方式,此方法适合用在需要对文本进行精细控制的定制化控件上.此方法特别底层而让调用方法比较复杂,本文告诉大家一些简单的使 ...

  3. VSCode 在 windows 下默认添加 _WIN32 的问题

    现象 在 VSCode 在 windows 下环境中使用时,会默认添加 _WIN32 ,会出现查看代码时,出现错误提示,现象如下 检测到 #include 错误.请更新 includePath.已为此 ...

  4. vue使用websoket(非封装)

    上代码: create:function(){ this.initWebpack() } methods:{ initWebpack(){//初始化websocket           let us ...

  5. 【GUI软件】小红书搜索结果批量采集,支持多个关键词同时抓取!

    目录 一.背景介绍 1.1 爬取目标 1.2 演示视频 1.3 软件说明 二.代码讲解 2.1 爬虫采集模块 2.2 软件界面模块 2.3 日志模块 三.获取源码及软件 一.背景介绍 1.1 爬取目标 ...

  6. LVS负载均衡(6)--LVS调度算法详解

    目录 1. LVS调度算法详解 1.1 静态调度算法 1.1.1 RR调度算法 1.1.2 WRR调度算法 1.1.3 SH调度算法 1.1.4 DH调度算法 1.2 动态调度算法 1.2.1 LC调 ...

  7. Ubuntu空间不足,如何扩容

    扩容多少看自己需求 点击确定然后打开虚拟机 使用工具的第一种方法 使用Ubuntu自带的disk,直接搜软件disk,点击进去 选择自己要扩容的磁盘 点击设置,选择resize 你要扩容到多少就拖动到 ...

  8. fastposter v2.9.2 最简海报生成器

    fastposter v2.9.2 程序员必备海报生成器 fastposter海报生成器是一款快速开发海报的工具.只需上传一张背景图,在对应的位置放上组件(文字.图片.二维.头像)即可生成海报. 点击 ...

  9. 一次glide内存泄漏排查分析

    glide是一款非常优秀的图片加载框架,目前很多项目在使用.提供了非常方法,在此,笔者就不一一列举了,可以到官网查找. 目前项目在做内存排查,因为是车机项目,之前开发的时候没有注意内存方面的问题(车机 ...

  10. vue和react的相同点和不同点

    Vue和React作为现代前端开发中流行的两个JavaScript框架,它们有诸多相似之处,同时也存在一些关键性的不同.以下是Vue和React的一些主要相同点和不同点: 相同点: 虚拟DOM:Vue ...