K-means聚类是一种非常流行的聚类算法
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聚类是一种非常流行的聚类算法的更多相关文章
- 软件——机器学习与Python,聚类,K——means
K-means是一种聚类算法: 这里运用k-means进行31个城市的分类 城市的数据保存在city.txt文件中,内容如下: BJ,2959.19,730.79,749.41,513.34,467. ...
- DBSCAN聚类︱scikit-learn中一种基于密度的聚类方式
一.DBSCAN聚类概述 基于密度的方法的特点是不依赖于距离,而是依赖于密度,从而克服基于距离的算法只能发现"球形"聚簇的缺点. DBSCAN的核心思想是从某个核心点出发,不断向密 ...
- PolyCluster: Minimum Fragment Disagreement Clustering for Polyploid Phasing 多聚类:用于多倍体的最小碎片不一致聚类
摘要 分型是计算生物学的一个新兴领域,在临床决策和生物医学科学中有着重要的应用. 虽然机器学习技术在许多生物医学应用中显示出巨大的潜力,但它们在分型中的用途尚未完全理解. 在本文中,我们研究了基于聚类 ...
- 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 ...
- 一种局部二值化算法:Sauvola算法
之前接触过全局二值化(OTSU算法),还有OPENCV提供的自适应二值化,最近又了解到一种新的局部二值化算法,Sauvola算法. 转载自:http://www.dididongdong.com/ar ...
- C/C++中几种经典的垃圾回收算法
1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...
- 有两个序列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 * ...
- C++ 几种经典的垃圾回收算法
之前遇到了一篇好文(https://blog.csdn.net/wallwind/article/details/6889917)准备学习一下的,课程繁忙就忘记了,今日得闲,特来补一下. 自己写一遍加 ...
- Self Organizing Maps (SOM): 一种基于神经网络的聚类算法
自组织映射神经网络, 即Self Organizing Maps (SOM), 可以对数据进行无监督学习聚类.它的思想很简单,本质上是一种只有输入层--隐藏层的神经网络.隐藏层中的一个节点代表一个需要 ...
- [转]Javascript中几种较为流行的继承方式
出处:http://www.jianshu.com/p/a6c005228a75 开篇 从'严格'意义上说,javascript并不是一门真正的面向对象语言.这种说法原因一般都是觉得javascrip ...
随机推荐
- Linux 根文件系统的移植(从入门到精通)
一.简介 提到操作系统的安装,还得从大学的时候说起,刚入学的时,朋友的系统本崩了,跑去电脑城换个系统花了40大洋,震惊了贫穷的我.好像发现了商机,果断开始了折腾自己的电脑,然后用朋友的电脑进行测试,由 ...
- .NET CORE 完美支持AOT 的 ORM SqlSugar 教程
1.AOT适合产场 Aot适合工具类型的项目使用,优点禁止反编 ,第一次启动快,业务型项目或者反射多的项目不适合用AOT AOT更新记录: 实实在在经过实践的AOT ORM 5.1.4.117 +支持 ...
- JUC并发编程学习笔记(一)认知进程和线程
进程和线程 进程 一个程序,如QQ.exe,是程序的集合 一个进程往往可以包含多个线程,至少包含一个 java默认有两个线程,GC垃圾回收线程和Main线程 线程:一个进程中的各个功能 java无法真 ...
- VSCode:所选环境中没有可用的Pip安装程序
VSCode:所选环境中没有可用的Pip安装程序 然后我尝试格式化我的代码,VSCode说没有安装autopep8,可以通过Pip安装 . 但是,当我尝试通过Pip安装时,它会说 There is n ...
- 如何加速C++文件的编译速度?
一.为什么慢? 重要的一个原因是C++的基本 头文件-源文件的编译模型: 每个源文件为一个编译单元 头文件数量多,可能会包含上百甚至上千个头文件 存在重复解析,每个编译单元中,这些头文件都要从硬盘里读 ...
- java里面的方法。
java里面的方法. java方法是语句的组合,他们在一起执行一个功能. 方法是解决一类问题的步骤的有序组合 方法包含于类或对象中 方法在程序中被创建在其他地方被引用 方法类似于其他语言里面的函数 e ...
- 了解Oracle中的Dual系统表
首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...
- 记一次ThreadLocal中的用户信息混乱问题
前言 记录一次开发中遇到的关于 ThreadLocal 问题,场景是数据库表中的操作人总是无缘无故的被更改,排查了几遍代码才发现是 ThreadLocal 没有及时清理导致的. 一.为什么使用 Thr ...
- .NET实现获取NTP服务器时间并同步(附带Windows系统启用NTP服务功能)
对某个远程服务器启用和设置NTP服务(Windows系统) 打开注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Tim ...
- ASP.NET Core如何禁用模型验证(或者从模型状态中移除某些属性)?
这是一篇4年前的文章:[经验分享]在ASP.NET Core中,如果禁用某个请求的模型验证? 事隔多年,又有网友问到这个问题.我就来重新整理一下,顺便扩展一下之前的解决办法. ===== 这是一个来自 ...