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.pswp.cn/news/386150.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386150.shtml
英文地址,請注明出處:http://en.pswp.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;還在迷茫躊躇中的后浪們&…

html知識筆記(二)——div、table、a標簽

div標簽&#xff1a;我們把一些標簽放進<div>里&#xff0c;劃分出一個獨立的邏輯部分。為了使邏輯更加清晰&#xff0c;我們可以為這一個獨立的邏輯部分設置一個名稱&#xff0c;用id屬性來為<div>提供唯一的名稱&#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;也在一些小…

css知識筆記(一)——基礎知識、選擇器、元素分類

CSS全稱為“層疊樣式表 (Cascading Style Sheets)”&#xff0c;它主要是用于定義HTML內容在瀏覽器內的顯示樣式&#xff0c;如文字大小、顏色、字體加粗等。 如下列代碼&#xff1a; p{font-size:12px;color:red;font-weight:bold; } 使用CSS樣式的一個好處是通過定義某個樣式…

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篇 …

css知識筆記(五)——css樣式設置小技巧

水平居中設置-行內元素 如果被設置元素為文本、圖片等行內元素時&#xff0c;水平居中是通過給父元素設置 text-align:center 來實現的。如下代碼&#xff1a; html代碼&#xff1a; <body><div class"txtCenter">我是文本&#xff0c;哈哈&#xff0c;我…

HTML如何添加錨點,干貨滿滿

前言 昨天有幸去字節面試了&#xff0c;順便拿到了offer&#xff0c;把還記得的東西寫下來&#xff0c;供大家參考一下。 CSS篇 讓一個元素水平垂直居中&#xff0c;到底有多少種方案&#xff1f;浮動布局的優點&#xff0c;缺點&#xff1f;清除浮動的方式&#xff1f;使用di…