java实现k-means算法(用的鸢尾花iris的数据集,从mysq数据库中读取数据)

k-means算法又称k-均值算法,是机器学习聚类算法中的一种,是一种基于形心的划分方法,其中每个簇的中心都用簇中所有对象的均值来表示。其思想如下:

输入:

  • k:簇的数目;
  • D:包含n个对象的数据集。
输出:k个簇的集合。

方法:

  1. 从D中随机选择几个对象作为起始质心;
  2. 对每个质心,计算每个数据到各个质心的距离,并把这些点分配到离该质心最短的距离的簇;
  3. 对每个簇,计算簇中所有点的均值并将此均值作为新的质心;
  4. 将数据点按照新的中心重新聚类;
  5. 重复【步骤3】,直到质心不再发生变化(新的质心和原来的质心相等);
  6. 输出聚类结果。
算法实现:

木羊的k-means算法实现包括5各类。其中,DBConnection.java用于连接数据库,SelectData.java用于从数据库里读取数据,Point.java存放点对象模型,ManagePoint.java是对点的操作,Kmeans.java是算法的核心思想及主函数入口。以下分别给出各个类的详细代码:

DBConnection.java

数据集获取,在机器学习数据集获取官方网站UCI中点击打开链接,木羊已经把该数据集从txt文档中插入到数据库,并去除了最后一列(花类别)。读者若不熟悉数据库的读写,请百度。若木羊有时间,会在后面的博文中补充把txt文档内容读到数据库中的内容。

<span style="font-size:18px;">package db;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;/*** * 数据库连接类* */
public class DBConnection {public static final String driver = "com.mysql.jdbc.Driver";public static final String url = "jdbc:mysql://localhost:3306/mydb";public static final String user = "root";public static final String pwd = "123";public static Connection dBConnection() {Connection con = null;try {// 加载mysql驱动器Class.forName(driver);// 建立数据库连接con = DriverManager.getConnection(url, user, pwd);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blockSystem.out.println("加载驱动器失败");e.printStackTrace();} catch (SQLException e) {// TODO Auto-generated catch blockSystem.out.println("注册驱动器失败");e.printStackTrace();}return con;}
}</span>

数据库中的数据字段如下(共有150条数据):


SelectData.java

package dao;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;import model.Point;
import db.DBConnection;/*** * 取出数据* * @return pointList* */
public class SelectData {public static final String SELECT = "select* from iris_Kmeans";public ArrayList<Point> getPoints() throws SQLException {ArrayList<Point> pointsList = new ArrayList<Point>();Connection con = DBConnection.dBConnection();ResultSet rs;// 创建一个PreparedStatement对象PreparedStatement pstmt = con.prepareStatement(SELECT);rs = pstmt.executeQuery();while (rs.next()) {Point point = new Point();point.setX(rs.getDouble(2));point.setY(rs.getDouble(3));point.setZ(rs.getDouble(4));point.setW(rs.getDouble(5));pointsList.add(point);}System.out.println("数据集: " + pointsList);pstmt.close();rs.close();con.close();return pointsList;}
}

Point.java

此处要注意重写equal和hashcode方法以便后面质心的比较。


package model;public class Point {private double x;private double y;private double z;private double w;public double getX() {return x;}public void setX(double x) {this.x = x;}public double getY() {return y;}public void setY(double y) {this.y = y;}public double getZ() {return z;}public void setZ(double z) {this.z = z;}public double getW() {return w;}public void setW(double w) {this.w = w;}public Point() {}public Point(double x, double y, double z, double w) {super();this.x = x;this.y = y;this.z = z;this.w = w;}@Overridepublic String toString() {return "Point [ x=" + x + ", y=" + y + ", z=" + z + ", w=" + w + "]";}@Overridepublic boolean equals(Object obj) {Point point = (Point) obj;if (this.getX() == point.getX() && this.getY() == point.getY()&& this.getZ() == point.getZ() && this.getW() == point.getW()) {return true;}return false;}@Overridepublic int hashCode() {return (int) (x + y + z + w);}
}


ManagePoint.java

该类包含了3个方法,分别用于计算两个点的欧氏距离,比较前后两个质心是否相同,更新质心。

package util;import java.util.ArrayList;
import java.util.Map;import model.Point;public class ManagePoint {/*** * 计算两点之间的距离* * @param p*            第一个点* @param q*            第二个点* @return distance* */public double getDistance(Point p, Point q) {double dx = p.getX() - q.getX();double dy = p.getY() - q.getY();double dz = p.getZ() - q.getZ();double dw = p.getW() - q.getW();double distance = Math.sqrt(dx * dx + dy * dy + dz * dz + dw * dw);return distance;}/*** 判断前后两个质心是否相同* * @param nowCenterCluster*            现在的质心* @param lastCenterCluster*            上一次的质心* @return boolean* */public boolean isEqual(Map<Point, ArrayList<Point>> lastCenterCluster,Map<Point, ArrayList<Point>> nowCenterCluster) {boolean contain = false;if (lastCenterCluster == null)return false;else {for (Point point : nowCenterCluster.keySet()) {contain = lastCenterCluster.containsKey(point);}if (contain)return true;}return false;}/*** * 计算新的质心* * @param value*            map中的值,存放簇中的所有点* @return point* */public Point getNewCenter(ArrayList<Point> value) {double sumX = 0, sumY = 0, sumZ = 0, sumW = 0;for (Point point : value) {sumX += point.getX();sumY += point.getY();sumZ += point.getZ();sumW += point.getW();}System.out.println("新的质心: (" + sumX / value.size() + "," + sumY/ value.size() + "," + sumZ / value.size() + "," + sumW/ value.size() + ")");Point point = new Point();point.setX(sumX / value.size());point.setY(sumY / value.size());point.setZ(sumZ / value.size());point.setW(sumW / value.size());return point;}
}

Kmeans.java

木羊把簇存在hashmap里,其中key存放该簇的质心,value存放该簇的所有点。特别注意的是,为了使最终聚类相对较理想,随机选择的三个初始质心应该在[0-50)、[50-100)、[100-150]三个区间内。

package util;import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;import model.Point;
import dao.SelectData;public class Kmeans {public Map<Point, ArrayList<Point>> executeKmeans(int k) {ArrayList<Point> dataList = new ArrayList<Point>();// 存放原始数据Map<Point, ArrayList<Point>> nowCenterClusterMap = new HashMap<Point, ArrayList<Point>>();// 当前质心及其簇内的点Map<Point, ArrayList<Point>> lastCenterClusterMap = null;// 上一个质心及其簇内的点try {dataList = new SelectData().getPoints();// 随机创建K个点作为起始质心Random rd = new Random();int[] initIndex = { 50, 50, 50 };int[] tempIndex = { 0, 50, 100 };System.out.println("起始质心下标: ");for (int i = 0; i < k; i++) {int index = rd.nextInt(initIndex[i]) + tempIndex[i];System.out.println("第" + (i + 1) + "个 : " + index);nowCenterClusterMap.put(dataList.get(index),new ArrayList<Point>());}// 输出起始质心System.out.println("起始质心: ");for (Point point : nowCenterClusterMap.keySet())System.out.println("key:  " + point);// 将数据点point加入配到离其最近的map的value中ManagePoint managePoint = new ManagePoint();while (true) {for (Point point : dataList) {double shortestDistance = Double.MAX_VALUE;// 初始化最短距离为Double的最大值Point key = null;for (Entry<Point, ArrayList<Point>> entry : nowCenterClusterMap.entrySet()) {// 计算质心与各点间的距离double distance = managePoint.getDistance(entry.getKey(), point);if (distance < shortestDistance) {shortestDistance = distance;key = entry.getKey();}}nowCenterClusterMap.get(key).add(point);}// 如果新的质心与上次的质心相等,则退出整个循环if (managePoint.isEqual(lastCenterClusterMap,nowCenterClusterMap)) {System.out.println("相等了。");break;}// 更新质心lastCenterClusterMap = nowCenterClusterMap;nowCenterClusterMap = new HashMap<Point, ArrayList<Point>>();System.out.println("------------------------------------------------------------------");for (Entry<Point, ArrayList<Point>> entry : lastCenterClusterMap.entrySet()) {nowCenterClusterMap.put(managePoint.getNewCenter(entry.getValue()),new ArrayList<Point>());}}} catch (SQLException e) {// TODO Auto-generated catch blockSystem.out.println("数据库操作失败");e.printStackTrace();}return nowCenterClusterMap;}public static void main(String[] args) {int K = 3;// 分为三个类Map<Point, ArrayList<Point>> result = new Kmeans().executeKmeans(K);// 输出分类System.out.println("===========聚类结果: ============");for (Entry<Point, ArrayList<Point>> entry : result.entrySet()) {System.out.println("\n" + "稳定的质心: " + entry.getKey());System.out.println("该簇的大小: " + entry.getValue().size());System.out.println("簇里的点:" + entry.getValue());}}
}

以上代码均从MyEclipse上复制粘贴而来,亲测可运行,结果如下:



经测试,无论初始质心被随机选择成哪3个,最终稳定的质心都不变。

(欢迎讨论。代码尚有不完善之处,请多多指教。转载请注明出处。)



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

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

相关文章

CSS清除默认样式,聪明人已经收藏了!

1、ant-design的使用总结及常用组件和他们的基本用法? ant-design为React&#xff0c;Angular和Vue都提供了组件&#xff0c;同时为PC和移动端提供了常用的基础组件。ant-design提供的demo非常的丰富并且样式能够基本的覆盖开发需求。antd的Demo因为是多人编写的&#xff0c;…

浅谈“==”、equals和hashcode,以及map的遍历方法(可用作上一篇k-means博文参考)

前不久看到一个公司的面试题&#xff0c;问到“”和“equals”的区别&#xff0c;些许上答不上来&#xff0c;于是木羊搜索并整理了一下。此外&#xff0c;木羊前面写了k-means算法实现的博文&#xff0c;其中提到要重写equals和hashcode类&#xff0c;看完这篇博文&#xff0c…

CSS清除默认样式,面试篇

前言 过完年了&#xff0c;准备实习的你是已经在实习了&#xff0c;还是已经辞职回家过年&#xff0c;准备年后重新找工作呢&#xff0c;又或者是准备2021年春招&#xff1f; 那么还没没踏出校门或者是刚出校门没多久的同学们该如何准备前端校招的面试呢&#xff1f; 学习建议…

CSS的三种基础选择器,面试必问

前言 最近在准备面试&#xff0c;然后复习下之前写过的项目&#xff0c;书籍&#xff0c;笔记&#xff0c;文章。一看很多知识点都没有印象&#xff0c;最可拍的是连自己为了防止忘记写的文章竟然都感觉不是自己写的。有些开始怀疑人生了。 好了&#xff0c;废话少说&#xf…

html知识笔记(一)——head和body标签

标签的用途&#xff1a;我们学习网页制作时&#xff0c;常常会听到一个词&#xff0c;语义化。那么什么叫做语义化呢&#xff0c;说的通俗点就是&#xff1a;明白每个标签的用途&#xff08;在什么情况下我可以使用这个标签才合理&#xff09;比如&#xff0c;网页上的文章的标…

CSS的三种定位,100%好评!

前言 跳槽&#xff0c;这在 IT 互联网圈是非常普遍的&#xff0c;也是让自己升职加薪&#xff0c;走上人生巅峰的重要方式。那么作为一个普通的Android程序猿&#xff0c;我们如何才能斩获大厂offer 呢&#xff1f; 疫情向好、面试在即&#xff0c;还在迷茫踌躇中的后浪们&…

CSS的三种定位,成功入职字节跳动

前言 校招 -1 年 这个阶段还属于成长期&#xff0c;更需要看重的是你的基础和热情。对于 JS 基础&#xff0c;计算机基础&#xff0c;网络通信&#xff0c;算法等部分的要求会相对高一些。毕竟这个阶段比较难考察你的业务项目中的沉淀&#xff0c;所以只能从基础部分入手考察。…

html知识笔记(三)——img标签、form表单

<img>标签&#xff1a;在网页中插入图片。 语法&#xff1a; <img src"图片地址" alt"下载失败时的替换文本" title "提示文本"> 举例&#xff1a; <img src "myimage.gif" alt "My Image" title "…

CSS的三种定位,月薪30K

毕业工作一年之后&#xff0c;有了转行的想法&#xff0c;偶然接触到程序员这方面&#xff0c;产生了浓厚且强烈的兴趣&#xff0c;开始学习前端&#xff0c;成功收割了大厂offer&#xff0c;开始了我的程序员生涯。 在自学过程中有过一些小厂的面试经历&#xff0c;也在一些小…

HTML列表标签,大牛最佳总结

前言 跳槽&#xff0c;这在 IT 互联网圈是非常普遍的&#xff0c;也是让自己升职加薪&#xff0c;走上人生巅峰的重要方式。那么作为一个普通的Android程序猿&#xff0c;我们如何才能斩获大厂offer 呢&#xff1f; 疫情向好、面试在即&#xff0c;还在迷茫踌躇中的后浪们&…

css知识笔记(二)——盒子模型

盒子模型 类比月饼&#xff1a;礼盒是最外层&#xff0c;里面的月饼&#xff08;伍仁&#xff09;是页面元素&#xff0c;比如一个div&#xff1b;"伍仁"本身是盒子的内容&#xff08;可以是文字、图片、另一个标签元素&#xff09;&#xff0c;月饼和月饼盒之间的距…

HTML列表标签,讲的明明白白!

前言 过完年了&#xff0c;准备实习的你是已经在实习了&#xff0c;还是已经辞职回家过年&#xff0c;准备年后重新找工作呢&#xff0c;又或者是准备2021年春招&#xff1f; 那么还没没踏出校门或者是刚出校门没多久的同学们该如何准备前端校招的面试呢&#xff1f; 学习路线…

css学习笔记(三)——布局模型

布局模型与盒模型一样都是 CSS 最基本、 最核心的概念。 但布局模型是建立在盒模型基础之上&#xff0c;又不同于我们常说的 CSS 布局样式或 CSS 布局模板。如果说布局模型是本&#xff0c;那么 CSS 布局模板就是末了&#xff0c;是外在的表现形式。 CSS包含3种基本的布局模型…

HTML列表标签,赶紧收藏!

前言 前端校招面试题主要内容包括html&#xff0c;css&#xff0c;前端基础&#xff0c;前端核心&#xff0c;前端进阶&#xff0c;移动端开发&#xff0c;计算机基础&#xff0c;算法与数据结构&#xff0c;设计模式&#xff0c;项目等等。&#xff08;本文资料 适合0-2年&am…

css知识笔记(四)——代码简写、颜色值、长度值

盒模型代码简写 还记得在讲盒模型时外边距(margin)、内边距(padding)和边框(border)设置上下左右四个方向的边距是按照顺时针方向设置的&#xff1a;上右下左。具体应用在margin和padding的例子如下&#xff1a; margin:10px 15px 12px 14px;/*上设置为10px、右设置为15px、下设…

HTML如何添加锚点,分享一点面试小经验

前言 过完年了&#xff0c;准备实习的你是已经在实习了&#xff0c;还是已经辞职回家过年&#xff0c;准备年后重新找工作呢&#xff0c;又或者是准备2021年春招&#xff1f; 那么还没没踏出校门或者是刚出校门没多久的同学们该如何准备前端校招的面试呢&#xff1f; CSS篇 …

HTML如何添加锚点,干货满满

前言 昨天有幸去字节面试了&#xff0c;顺便拿到了offer&#xff0c;把还记得的东西写下来&#xff0c;供大家参考一下。 CSS篇 让一个元素水平垂直居中&#xff0c;到底有多少种方案&#xff1f;浮动布局的优点&#xff0c;缺点&#xff1f;清除浮动的方式&#xff1f;使用di…

JavaScript知识笔记(一)——入门、语句、注释、变量、函数、输出内容、对话框、窗口

JavaScript可以提供漂亮的网页、令用户满意的上网体验。 1.增强页面动态效果(如:下拉菜单、图片轮播、信息滚动等) 2.实现页面与用户之间的实时、动态交互(如:用户注册、登陆验证等) 引用JavaScript&#xff1a; 一、使用<script>标签在HTML文件中添加JavaScript代码&am…

HTML如何添加锚点,总结到位

标签语义化&#xff1a; 语义和默认样式的区别&#xff1a; 默认样式是浏览器设定的一些常用tag的表现形式&#xff1b;语义化的主要目的就是让大家直观的认识标签和属性的用途和作用&#xff1b; 标签语义化作用&#xff1a; 当只有HTML页面时&#xff0c;没有CSS&#xf…

JavaScript知识笔记(二)——事件

事件&#xff1a; JavaScript 创建动态页面。事件是可以被 JavaScript 侦测到的行为。 网页中的每个元素都可以产生某些可以触发 JavaScript 函数或程序的事件。 比如说&#xff0c;当用户单击按钮或者提交表单数据时&#xff0c;就发生一个鼠标单击&#xff08;onclick&#x…