使用Java实现K-Means聚类算法

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

 

关于K-Means介绍很多,还不清楚可以查一些相关资料。

个人对其实现步骤简单总结为4步:

1.选出k值,随机出k个起始质心点。 
 
2.分别计算每个点和k个起始质点之间的距离,就近归类。 
 
3.最终中心点集可以划分为k类,分别计算每类中新的中心点。 
 

4.重复2,3步骤对所有点进行归类,如果当所有分类的质心点不再改变,则最终收敛。

 

下面贴代码。

1.入口类,基本读取数据源进行训练然后输出。 数据源文件和源码后面会补上。

package com.hyr.kmeans;import au.com.bytecode.opencsv.CSVReader;import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;public class KmeansMain {public static void main(String[] args) throws IOException {// 读取数据源文件CSVReader reader = new CSVReader(new FileReader("src/main/resources/data.csv")); // 数据源FileWriter writer = new FileWriter("src/main/resources/out.csv");List<String[]> myEntries = reader.readAll(); // 6.8, 12.6// 转换数据点集List<Point> points = new ArrayList<Point>(); // 数据点集for (String[] entry : myEntries) {points.add(new Point(Float.parseFloat(entry[0]), Float.parseFloat(entry[1])));}int k = 6; // K值int type = 1;KmeansModel model = Kmeans.run(points, k, type);writer.write("====================   K is " + model.getK() + " ,  Object Funcion Value is " + model.getOfv() + " ,  calc_distance_type is " + model.getCalc_distance_type() + "   ====================\n");int i = 0;for (Cluster cluster : model.getClusters()) {i++;writer.write("====================   classification " + i + "   ====================\n");for (Point point : cluster.getPoints()) {writer.write(point.toString() + "\n");}writer.write("\n");writer.write("centroid is " + cluster.getCentroid().toString());writer.write("\n\n");}writer.close();}}

 

2.最终生成的模型类,也就是最终训练好的结果。K值,计算的点距离类型以及object function value值。

package com.hyr.kmeans;import java.util.ArrayList;
import java.util.List;public class KmeansModel {private List<Cluster> clusters = new ArrayList<Cluster>();private Double ofv;private int k;  // k值private int calc_distance_type;public KmeansModel(List<Cluster> clusters, Double ofv, int k, int calc_distance_type) {this.clusters = clusters;this.ofv = ofv;this.k = k;this.calc_distance_type = calc_distance_type;}public List<Cluster> getClusters() {return clusters;}public Double getOfv() {return ofv;}public int getK() {return k;}public int getCalc_distance_type() {return calc_distance_type;}
}

 

3.数据集点对象,包含点的维度,代码里只给出了x轴,y轴二维。以及点的距离计算。通过类型选择距离公式。给出了几种常用的距离公式。

package com.hyr.kmeans;public class Point {private Float x;     // x 轴private Float y;    // y 轴public Point(Float x, Float y) {this.x = x;this.y = y;}public Float getX() {return x;}public void setX(Float x) {this.x = x;}public Float getY() {return y;}public void setY(Float y) {this.y = y;}@Overridepublic String toString() {return "Point{" +"x=" + x +", y=" + y +'}';}/*** 计算距离** @param centroid 质心点* @param type* @return*/public Double calculateDistance(Point centroid, int type) {// TODODouble result = null;switch (type) {case 1:result = calcL1Distance(centroid);break;case 2:result = calcCanberraDistance(centroid);break;case 3:result = calcEuclidianDistance(centroid);break;}return result;}/*计算距离公式*/private Double calcL1Distance(Point centroid) {double res = 0;res = Math.abs(getX() - centroid.getX()) + Math.abs(getY() - centroid.getY());return res / (double) 2;}private double calcEuclidianDistance(Point centroid) {return Math.sqrt(Math.pow((centroid.getX() - getX()), 2) + Math.pow((centroid.getY() - getY()), 2));}private double calcCanberraDistance(Point centroid) {double res = 0;res = Math.abs(getX() - centroid.getX()) / (Math.abs(getX()) + Math.abs(centroid.getX()))+ Math.abs(getY() - centroid.getY()) / (Math.abs(getY()) + Math.abs(centroid.getY()));return res / (double) 2;}@Overridepublic boolean equals(Object obj) {Point other = (Point) obj;if (getX().equals(other.getX()) && getY().equals(other.getY())) {return true;}return false;}
}

 

4.训练后最终得到的分类。包含该分类的质点,属于该分类的点集合该分类是否收敛。

package com.hyr.kmeans;import java.util.ArrayList;
import java.util.List;public class Cluster {private List<Point> points = new ArrayList<Point>(); // 属于该分类的点集private Point centroid; // 该分类的中心质点private boolean isConvergence = false;public Point getCentroid() {return centroid;}public void setCentroid(Point centroid) {this.centroid = centroid;}@Overridepublic String toString() {return centroid.toString();}public List<Point> getPoints() {return points;}public void setPoints(List<Point> points) {this.points = points;}public void initPoint() {points.clear();}public boolean isConvergence() {return isConvergence;}public void setConvergence(boolean convergence) {isConvergence = convergence;}
}

 

5.K-Meams训练类。按照上面所说四个步骤不断进行训练。

package com.hyr.kmeans;import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class Kmeans {/*** kmeans** @param points 数据集* @param k      K值* @param k      计算距离方式*/public static KmeansModel run(List<Point> points, int k, int type) {// 初始化质心点List<Cluster> clusters = initCentroides(points, k);while (!checkConvergence(clusters)) { // 所有分类是否全部收敛// 1.计算距离对每个点进行分类// 2.判断质心点是否改变,未改变则该分类已经收敛// 3.重新生成质心点initClusters(clusters); // 重置分类中的点classifyPoint(points, clusters, type);// 计算距离进行分类recalcularCentroides(clusters); // 重新计算质心点}// 计算目标函数值Double ofv = calcularObjetiFuncionValue(clusters);KmeansModel kmeansModel = new KmeansModel(clusters, ofv, k, type);return kmeansModel;}/*** 初始化k个质心点** @param points 点集* @param k      K值* @return 分类集合对象*/private static List<Cluster> initCentroides(List<Point> points, Integer k) {List<Cluster> centroides = new ArrayList<Cluster>();// 求出数据集的范围(找出所有点的x最小、最大和y最小、最大坐标。)Float max_X = Float.NEGATIVE_INFINITY;Float max_Y = Float.NEGATIVE_INFINITY;Float min_X = Float.POSITIVE_INFINITY;Float min_Y = Float.POSITIVE_INFINITY;for (Point point : points) {max_X = max_X < point.getX() ? point.getX() : max_X;max_Y = max_Y < point.getY() ? point.getY() : max_Y;min_X = min_X > point.getX() ? point.getX() : min_X;min_Y = min_Y > point.getY() ? point.getY() : min_Y;}System.out.println("min_X" + min_X + ",max_X:" + max_X + ",min_Y" + min_Y + ",max_Y" + max_Y);// 在范围内随机初始化k个质心点Random random = new Random();// 随机初始化k个中心点for (int i = 0; i < k; i++) {float x = random.nextFloat() * (max_X - min_X) + min_X;float y = random.nextFloat() * (max_Y - min_Y) + min_X;Cluster c = new Cluster();Point centroide = new Point(x, y); // 初始化的随机中心点c.setCentroid(centroide);centroides.add(c);}return centroides;}/*** 重新计算质心点** @param clusters*/private static void recalcularCentroides(List<Cluster> clusters) {for (Cluster c : clusters) {if (c.getPoints().isEmpty()) {c.setConvergence(true);continue;}// 求均值,作为新的质心点Float x;Float y;Float sum_x = 0f;Float sum_y = 0f;for (Point point : c.getPoints()) {sum_x += point.getX();sum_y += point.getY();}x = sum_x / c.getPoints().size();y = sum_y / c.getPoints().size();Point nuevoCentroide = new Point(x, y); // 新的质心点if (nuevoCentroide.equals(c.getCentroid())) { // 如果质心点不再改变 则该分类已经收敛c.setConvergence(true);} else {c.setCentroid(nuevoCentroide);}}}/*** 计算距离,对点集进行分类** @param points   点集* @param clusters 分类* @param type     计算距离方式*/private static void classifyPoint(List<Point> points, List<Cluster> clusters, int type) {for (Point point : points) {Cluster masCercano = clusters.get(0); // 该点计算距离后所属的分类Double minDistancia = Double.MAX_VALUE; // 最小距离for (Cluster cluster : clusters) {Double distancia = point.calculateDistance(cluster.getCentroid(), type); // 点和每个分类质心点的距离if (minDistancia > distancia) { // 得到该点和k个质心点最小的距离minDistancia = distancia;masCercano = cluster; // 得到该点的分类}}masCercano.getPoints().add(point); // 将该点添加到距离最近的分类中}}private static void initClusters(List<Cluster> clusters) {for (Cluster cluster : clusters) {cluster.initPoint();}}/*** 检查收敛** @param clusters* @return*/private static boolean checkConvergence(List<Cluster> clusters) {for (Cluster cluster : clusters) {if (!cluster.isConvergence()) {return false;}}return true;}/*** 计算目标函数值** @param clusters* @return*/private static Double calcularObjetiFuncionValue(List<Cluster> clusters) {Double ofv = 0d;for (Cluster cluster : clusters) {for (Point point : cluster.getPoints()) {int type = 1;ofv += point.calculateDistance(cluster.getCentroid(), type);}}return ofv;}
}

 

最终训练结果:

====================   K is 6 ,  Object Funcion Value is 21.82857036590576 ,  calc_distance_type is 3   ====================
====================   classification 1   ====================
Point{x=3.5, y=12.5}centroid is Point{x=3.5, y=12.5}====================   classification 2   ====================
Point{x=6.8, y=12.6}
Point{x=7.8, y=12.2}
Point{x=8.2, y=11.1}
Point{x=9.6, y=11.1}centroid is Point{x=8.1, y=11.75}====================   classification 3   ====================
Point{x=4.4, y=6.5}
Point{x=4.8, y=1.1}
Point{x=5.3, y=6.4}
Point{x=6.6, y=7.7}
Point{x=8.2, y=4.5}
Point{x=8.4, y=6.9}
Point{x=9.0, y=3.4}centroid is Point{x=6.671428, y=5.2142863}====================   classification 4   ====================
Point{x=6.0, y=19.9}
Point{x=6.2, y=18.5}
Point{x=5.3, y=19.4}
Point{x=7.6, y=17.4}centroid is Point{x=6.275, y=18.800001}====================   classification 5   ====================
Point{x=0.8, y=9.8}
Point{x=1.2, y=11.6}
Point{x=2.8, y=9.6}
Point{x=3.8, y=9.9}centroid is Point{x=2.15, y=10.225}====================   classification 6   ====================
Point{x=6.1, y=14.3}centroid is Point{x=6.1, y=14.3}

 

代码下载地址:

http://download.csdn.net/download/huangyueranbbc/10267041

github: 

https://github.com/huangyueranbbc/KmeansDemo 

 

转载于:https://my.oschina.net/u/4074730/blog/3007470

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280430.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在PowerShell中显示高级进度条

如果你需要编写一些PowerShell脚本&#xff0c;尤其在处理一些相对复杂的任务时&#xff0c;你可能希望添加进度条的功能&#xff0c;以便随时可以了解进展情况。Write-Progress 这个命令可以帮助你完成简单的需求&#xff0c;请参考官方文档即可&#xff0c;但下图一个示例&am…

当检测到运动时如何自动打开门灯

If it’s dark out and someone comes to your door, you probably can’t see them unless your porch light is on. Furthermore, if a potential burglar approaches your front door, a motion light can help scare them away. 如果天黑了&#xff0c;有人进了您的门&…

在阿里,我们如何管理测试环境

为什么80%的码农都做不了架构师&#xff1f;>>> 作者&#xff1a;林帆&#xff08;花名金戟&#xff09;&#xff0c;阿里巴巴研发效能部技术专家 相关阅读&#xff1a;在阿里&#xff0c;我们如何管理代码分支 前言 阿里的许多实践看似简单&#xff0c;背后却蕴涵…

数据库_7_SQL基本操作——表操作

SQL基本操作——表操作 建表的过程就是声明列的过程。 表与字段是密不可分的。 一、新增数据表 create table [if not exists] 表名( 字段名字 数据类型, 字段名字 数据类型 -- 最后一行不需要逗号 )[表选项];if not exists:如果表名不存在&#xff0c;那么就创建&#xff0c;…

EXT.NET 更改lable和Text的颜色

2019独角兽企业重金招聘Python工程师标准>>> &#xfeff;&#xfeff; <ext:TextField ID"TextField1" " runat"server" FieldLabel"编号" LabelWidth"60" LabelAlign"Left" LabelStyle"color:red…

ubuntu系统备份和还原_如何使用Aptik在Ubuntu中备份和还原您的应用程序和PPA

ubuntu系统备份和还原If you need to reinstall Ubuntu or if you just want to install a new version from scratch, wouldn’t it be useful to have an easy way to reinstall all your apps and settings? You can easily accomplish this using a free tool called Apti…

AppDomainManager后门的实现思路

本文讲的是AppDomainManager后门的实现思路&#xff0c;0x00 前言从Casey SmithsubTee学到的一个技巧&#xff1a;针对.Net程序&#xff0c;通过修改AppDomainManager能够劫持.Net程序的启动过程。 如果劫持了系统常见.Net程序如powershell.exe的启动过程&#xff0c;向其添加…

所有内耗,都有解药。

你是否常常会有这种感觉&#xff1a;刚开始接手一件事情&#xff0c;脑海中已经幻想出无数个会发生的问题&#xff0c;心里也已笃定自己做不好&#xff1b;即使别人不经意的一句话&#xff0c;也会浮想一番&#xff0c;最终陷入自我怀疑&#xff1b;随便看到点什么&#xff0c;…

ABAP 通过sumbit调用另外一个程序使用job形式执行-简单例子

涉及到两个程序&#xff1a; ZTEST_ZUMA02 (主程序)ZTEST_ZUMA(被调用的程序&#xff0c;需要以后台job执行)"ztest_zuma 的代码DATA col TYPE i VALUE 0.DO 8 TIMES.MESSAGE JOB HERE TYPE S.ENDDO.程序ZTEST_ZUMA是在程序ZTEST_ZUMA02中以job的形式调用的&#xff0c;先…

那些影响深远的弯路

静儿最近反思很多事情&#xff0c;不仅是当时做错了。错误定式形成的思维习惯对自己的影响比事情本身要大的多。经常看到周围的同事&#xff0c;非常的羡慕。他们都很聪明、有自己的方法。就算有些同事工作经验相对少一些&#xff0c;但是就像在废墟上创建一个辉煌的城市要比在…

如何使用APTonCD备份和还原已安装的Ubuntu软件包

APTonCD is an easy way to back up your installed packages to a disc or ISO image. You can quickly restore the packages on another Ubuntu system without downloading anything. APTonCD是将安装的软件包备份到光盘或ISO映像的简便方法。 您可以在不下载任何东西的情况…

使用 Visual Studio 2022 调试Dapr 应用程序

使用Dapr 编写的是一个多进程的程序, 两个进程之间依赖于启动顺序来组成父子进程&#xff0c;使用Visual Studio 调试起来可能会比较困难&#xff0c;因为 Visual Studio 默认只会把你当前设置的启动项目的启动调试。好在有Visual Studio 扩展&#xff08;Microsoft Child Proc…

卸载 cube ui_如何还原Windows 8附带的已卸载现代UI应用程序

卸载 cube uiWindows 8 ships with built-in apps available on the Modern UI screen (formerly the Metro or Start screen), such as Mail, Calendar, Photos, Music, Maps, and Weather. Installing additional Modern UI apps is easy using the Windows Store, and unins…

Java Decompiler(Java反编译工具)

Java Decompiler官网地址&#xff1a;http://jd.benow.ca/ 官网介绍&#xff1a; The “Java Decompiler project” aims to develop tools in order to decompile and analyze Java 5 “byte code” and the later versions. JD-Core is a library that reconstructs Java sou…

MassTransit | 基于MassTransit Courier 实现 Saga 编排式分布式事务

Saga 模式Saga 最初出现在1987年Hector Garcaa-Molrna & Kenneth Salem发表的一篇名为《Sagas》的论文里。其核心思想是将长事务拆分为多个短事务&#xff0c;借助Saga事务协调器的协调&#xff0c;来保证要么所有操作都成功完成&#xff0c;要么运行相应的补偿事务以撤消先…

ccleaner无法更新_CCleaner正在静默更新关闭自动更新的用户

ccleaner无法更新CCleaner is forcing updates on users who specifically opt out of automatic updates. Users will only find out about these unwanted updates when they check the version number. CCleaner强制对专门选择退出自动更新的用户进行更新。 用户只有在检查版…

chrome浏览器崩溃_不只是您:Chrome浏览器在Windows 10的2018年4月更新中崩溃

chrome浏览器崩溃If your computer is hanging or freezing after installing the Windows 10 April 2018 Update you’re not alone, and Microsoft is aware of the problem. 如果在安装Windows 10 April 2018 Update之后计算机挂起或死机&#xff0c;您并不孤单&#xff0c;…

致敬青春岁月

昨天发生的一件神奇的事情。我们公司工会组织了一次小型的户外团建&#xff0c;有机会认识一些其他部门同事&#xff0c;没想到有一个同事小心地认出了我&#xff0c;然后还谈起了关于.NET技术和社区的一些发展的历史和故事。他在微软工作的时间比我久&#xff0c;但时空交错&a…

docker:自定义ubuntu/制作镜像引用/ubuntu换源更新

一、需求 1. 制作一个图像辨识的api&#xff0c;用到相同设置的ubuntu镜像&#xff0c;但是每次制作都要更新ubuntu和下载tesseract浪费半个到一个小时下载&#xff0c;所以制作一个自定义ubuntu几次镜像大大提高开发效率。 2. 制作ubuntu过程时&#xff0c;可以调试tesserac…

facebook人脸照片_为什么您的Facebook照片看起来如此糟糕(以及您可以如何做)...

facebook人脸照片Facebook is a popular platform for sharing photos, even though it’s not a very good one. They prioritize fast loading images over high quality ones. You can’t stop it from happening, but you can minimize the quality loss. Facebook是一个受…