欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

K均值聚類算法的Java版實(shí)現(xiàn)代碼示例

 更新時(shí)間:2017年12月08日 16:48:04   作者:cyxlzzs  
這篇文章主要介紹了K均值聚類算法的Java版實(shí)現(xiàn)代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。

1.簡(jiǎn)介

K均值聚類算法是先隨機(jī)選取K個(gè)對(duì)象作為初始的聚類中心。然后計(jì)算每個(gè)對(duì)象與各個(gè)種子聚類中心之間的距離,把每個(gè)對(duì)象分配給距離它最近的聚類中心。聚類中心以及分配給它們的對(duì)象就代表一個(gè)聚類。一旦全部對(duì)象都被分配了,每個(gè)聚類的聚類中心會(huì)根據(jù)聚類中現(xiàn)有的對(duì)象被重新計(jì)算。這個(gè)過程將不斷重復(fù)直到滿足某個(gè)終止條件。終止條件可以是沒有(或最小數(shù)目)對(duì)象被重新分配給不同的聚類,沒有(或最小數(shù)目)聚類中心再發(fā)生變化,誤差平方和局部最小。

2.什么是聚類

聚類是一個(gè)將數(shù)據(jù)集中在某些方面相似的數(shù)據(jù)成員進(jìn)行分類組織的過程,聚類就是一種發(fā)現(xiàn)這種內(nèi)在結(jié)構(gòu)的技術(shù),聚類技術(shù)經(jīng)常被稱為無監(jiān)督學(xué)習(xí)。

3.什么是k均值聚類

k均值聚類是最著名的劃分聚類算法,由于簡(jiǎn)潔和效率使得他成為所有聚類算法中最廣泛使用的。給定一個(gè)數(shù)據(jù)點(diǎn)集合和需要的聚類數(shù)目k,k由用戶指定,k均值算法根據(jù)某個(gè)距離函數(shù)反復(fù)把數(shù)據(jù)分入k個(gè)聚類中。

4.實(shí)現(xiàn)

Java代碼如下:

package org.algorithm;
import java.util.ArrayList;
import java.util.Random;
/** 
 * K均值聚類算法 
 */
public class Kmeans {
	private int k;
	// 分成多少簇 
	private int m;
	// 迭代次數(shù) 
	private int dataSetLength;
	// 數(shù)據(jù)集元素個(gè)數(shù),即數(shù)據(jù)集的長度 
	private ArrayList<float[]> dataSet;
	// 數(shù)據(jù)集鏈表 
	private ArrayList<float[]> center;
	// 中心鏈表 
	private ArrayList<ArrayList<float[]>> cluster;
	// 簇 
	private ArrayList<float> jc;
	// 誤差平方和,k越接近dataSetLength,誤差越小 
	private Random random;
	/** 
   * 設(shè)置需分組的原始數(shù)據(jù)集 
   * 
   * @param dataSet 
   */
	public void setDataSet(ArrayList<float[]> dataSet) {
		this.dataSet = dataSet;
	}
	/** 
   * 獲取結(jié)果分組 
   * 
   * @return 結(jié)果集 
   */
	public ArrayList<ArrayList<float[]>> getCluster() {
		return cluster;
	}
	/** 
   * 構(gòu)造函數(shù),傳入需要分成的簇?cái)?shù)量 
   * 
   * @param k 
   *      簇?cái)?shù)量,若k<=0時(shí),設(shè)置為1,若k大于數(shù)據(jù)源的長度時(shí),置為數(shù)據(jù)源的長度 
   */
	public Kmeans(int k) {
		if (k <= 0) {
			k = 1;
		}
		this.k = k;
	}
	/** 
   * 初始化 
   */
	private void init() {
		m = 0;
		random = new Random();
		if (dataSet == null || dataSet.size() == 0) {
			initDataSet();
		}
		dataSetLength = dataSet.size();
		if (k > dataSetLength) {
			k = dataSetLength;
		}
		center = initCenters();
		cluster = initCluster();
		jc = new ArrayList<float>();
	}
	/** 
   * 如果調(diào)用者未初始化數(shù)據(jù)集,則采用內(nèi)部測(cè)試數(shù)據(jù)集 
   */
	private void initDataSet() {
		dataSet = new ArrayList<float[]>();
		// 其中{6,3}是一樣的,所以長度為15的數(shù)據(jù)集分成14簇和15簇的誤差都為0 
		float[][] dataSetArray = new float[][] { { 8, 2 }, { 3, 4 }, { 2, 5 }, 
		        { 4, 2 }, { 7, 3 }, { 6, 2 }, { 4, 7 }, { 6, 3 }, { 5, 3 }, 
		        { 6, 3 }, { 6, 9 }, { 1, 6 }, { 3, 9 }, { 4, 1 }, { 8, 6 } };
		for (int i = 0; i < dataSetArray.length; i++) {
			dataSet.add(dataSetArray[i]);
		}
	}
	/** 
   * 初始化中心數(shù)據(jù)鏈表,分成多少簇就有多少個(gè)中心點(diǎn) 
   * 
   * @return 中心點(diǎn)集 
   */
	private ArrayList<float[]> initCenters() {
		ArrayList<float[]> center = new ArrayList<float[]>();
		int[] randoms = new int[k];
		Boolean flag;
		int temp = random.nextint(dataSetLength);
		randoms[0] = temp;
		for (int i = 1; i < k; i++) {
			flag = true;
			while (flag) {
				temp = random.nextint(dataSetLength);
				int j = 0;
				// 不清楚for循環(huán)導(dǎo)致j無法加1 
				// for(j=0;j<i;++j) 
				// { 
				// if(temp==randoms[j]); 
				// { 
				// break; 
				// } 
				// } 
				while (j < i) {
					if (temp == randoms[j]) {
						break;
					}
					j++;
				}
				if (j == i) {
					flag = false;
				}
			}
			randoms[i] = temp;
		}
		// 測(cè)試隨機(jī)數(shù)生成情況 
		// for(int i=0;i<k;i++) 
		// { 
		// System.out.println("test1:randoms["+i+"]="+randoms[i]); 
		// } 
		// System.out.println(); 
		for (int i = 0; i < k; i++) {
			center.add(dataSet.get(randoms[i]));
			// 生成初始化中心鏈表
		}
		return center;
	}
	/** 
   * 初始化簇集合 
   * 
   * @return 一個(gè)分為k簇的空數(shù)據(jù)的簇集合 
   */
	private ArrayList<ArrayList<float[]>> initCluster() {
		ArrayList<ArrayList<float[]>> cluster = new ArrayList<ArrayList<float[]>>();
		for (int i = 0; i < k; i++) {
			cluster.add(new ArrayList<float[]>());
		}
		return cluster;
	}
	/** 
   * 計(jì)算兩個(gè)點(diǎn)之間的距離 
   * 
   * @param element 
   *      點(diǎn)1 
   * @param center 
   *      點(diǎn)2 
   * @return 距離 
   */
	private float distance(float[] element, float[] center) {
		float distance = 0.0f;
		float x = element[0] - center[0];
		float y = element[1] - center[1];
		float z = x * x + y * y;
		distance = (float) Math.sqrt(z);
		return distance;
	}
	/** 
   * 獲取距離集合中最小距離的位置 
   * 
   * @param distance 
   *      距離數(shù)組 
   * @return 最小距離在距離數(shù)組中的位置 
   */
	private int minDistance(float[] distance) {
		float minDistance = distance[0];
		int minLocation = 0;
		for (int i = 1; i < distance.length; i++) {
			if (distance[i] < minDistance) {
				minDistance = distance[i];
				minLocation = i;
			} else if (distance[i] == minDistance) // 如果相等,隨機(jī)返回一個(gè)位置 
			{
				if (random.nextint(10) < 5) {
					minLocation = i;
				}
			}
		}
		return minLocation;
	}
	/** 
   * 核心,將當(dāng)前元素放到最小距離中心相關(guān)的簇中 
   */
	private void clusterSet() {
		float[] distance = new float[k];
		for (int i = 0; i < dataSetLength; i++) {
			for (int j = 0; j < k; j++) {
				distance[j] = distance(dataSet.get(i), center.get(j));
				// System.out.println("test2:"+"dataSet["+i+"],center["+j+"],distance="+distance[j]);
			}
			int minLocation = minDistance(distance);
			// System.out.println("test3:"+"dataSet["+i+"],minLocation="+minLocation); 
			// System.out.println(); 
			cluster.get(minLocation).add(dataSet.get(i));
			// 核心,將當(dāng)前元素放到最小距離中心相關(guān)的簇中
		}
	}
	/** 
   * 求兩點(diǎn)誤差平方的方法 
   * 
   * @param element 
   *      點(diǎn)1 
   * @param center 
   *      點(diǎn)2 
   * @return 誤差平方 
   */
	private float errorSquare(float[] element, float[] center) {
		float x = element[0] - center[0];
		float y = element[1] - center[1];
		float errSquare = x * x + y * y;
		return errSquare;
	}
	/** 
   * 計(jì)算誤差平方和準(zhǔn)則函數(shù)方法 
   */
	private void countRule() {
		float jcF = 0;
		for (int i = 0; i < cluster.size(); i++) {
			for (int j = 0; j < cluster.get(i).size(); j++) {
				jcF += errorSquare(cluster.get(i).get(j), center.get(i));
			}
		}
		jc.add(jcF);
	}
	/** 
   * 設(shè)置新的簇中心方法 
   */
	private void setNewCenter() {
		for (int i = 0; i < k; i++) {
			int n = cluster.get(i).size();
			if (n != 0) {
				float[] newCenter = { 0, 0 };
				for (int j = 0; j < n; j++) {
					newCenter[0] += cluster.get(i).get(j)[0];
					newCenter[1] += cluster.get(i).get(j)[1];
				}
				// 設(shè)置一個(gè)平均值 
				newCenter[0] = newCenter[0] / n;
				newCenter[1] = newCenter[1] / n;
				center.set(i, newCenter);
			}
		}
	}
	/** 
   * 打印數(shù)據(jù),測(cè)試用 
   * 
   * @param dataArray 
   *      數(shù)據(jù)集 
   * @param dataArrayName 
   *      數(shù)據(jù)集名稱 
   */
	public void printDataArray(ArrayList<float[]> dataArray, 
	      String dataArrayName) {
		for (int i = 0; i < dataArray.size(); i++) {
			System.out.println("print:" + dataArrayName + "[" + i + "]={" 
			          + dataArray.get(i)[0] + "," + dataArray.get(i)[1] + "}");
		}
		System.out.println("===================================");
	}
	/** 
   * Kmeans算法核心過程方法 
   */
	private void kmeans() {
		init();
		// printDataArray(dataSet,"initDataSet"); 
		// printDataArray(center,"initCenter"); 
		// 循環(huán)分組,直到誤差不變?yōu)橹?
		while (true) {
			clusterSet();
			// for(int i=0;i<cluster.size();i++) 
			// { 
			// printDataArray(cluster.get(i),"cluster["+i+"]"); 
			// } 
			countRule();
			// System.out.println("count:"+"jc["+m+"]="+jc.get(m)); 
			// System.out.println(); 
			// 誤差不變了,分組完成 
			if (m != 0) {
				if (jc.get(m) - jc.get(m - 1) == 0) {
					break;
				}
			}
			setNewCenter();
			// printDataArray(center,"newCenter"); 
			m++;
			cluster.clear();
			cluster = initCluster();
		}
		// System.out.println("note:the times of repeat:m="+m);//輸出迭代次數(shù)
	}
	/** 
   * 執(zhí)行算法 
   */
	public void execute() {
		long startTime = System.currentTimeMillis();
		System.out.println("kmeans begins");
		kmeans();
		long endTime = System.currentTimeMillis();
		System.out.println("kmeans running time=" + (endTime - startTime) 
		        + "ms");
		System.out.println("kmeans ends");
		System.out.println();
	}
}

5.說明:

具體代碼是從網(wǎng)上找的,根據(jù)自己的理解加了注釋和進(jìn)行部分修改,若注釋有誤還望指正

6.測(cè)試

package org.test;
import java.util.ArrayList;
import org.algorithm.Kmeans;
public class KmeansTest {
	public static void main(String[] args) 
	  {
		//初始化一個(gè)Kmean對(duì)象,將k置為10 
		Kmeans k=new Kmeans(10);
		ArrayList<float[]> dataSet=new ArrayList<float[]>();
		dataSet.add(new float[]{1,2});
		dataSet.add(new float[]{3,3});
		dataSet.add(new float[]{3,4});
		dataSet.add(new float[]{5,6});
		dataSet.add(new float[]{8,9});
		dataSet.add(new float[]{4,5});
		dataSet.add(new float[]{6,4});
		dataSet.add(new float[]{3,9});
		dataSet.add(new float[]{5,9});
		dataSet.add(new float[]{4,2});
		dataSet.add(new float[]{1,9});
		dataSet.add(new float[]{7,8});
		//設(shè)置原始數(shù)據(jù)集 
		k.setDataSet(dataSet);
		//執(zhí)行算法 
		k.execute();
		//得到聚類結(jié)果 
		ArrayList<ArrayList<float[]>> cluster=k.getCluster();
		//查看結(jié)果 
		for (int i=0;i<cluster.size();i++) 
		    {
			k.printDataArray(cluster.get(i), "cluster["+i+"]");
		}
	}
}

總結(jié):測(cè)試代碼已經(jīng)通過。并對(duì)聚類的結(jié)果進(jìn)行了查看,結(jié)果基本上符合要求。至于有沒有更精確的算法有待發(fā)現(xiàn)。具體的實(shí)踐還有待挖掘

總結(jié)

以上就是本文關(guān)于K均值聚類算法的Java版實(shí)現(xiàn)代碼示例的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

相關(guān)文章

  • Java并發(fā)編程之CountDownLatch原理詳解

    Java并發(fā)編程之CountDownLatch原理詳解

    這篇文章主要介紹了Java并發(fā)編程之CountDownLatch原理詳解,CountDownLatch類中使用了一個(gè)繼承自AQS的共享鎖Sync對(duì)象,構(gòu)造CountDownLatch對(duì)象時(shí)會(huì)將傳入的線程數(shù)值設(shè)為AQS的state值,需要的朋友可以參考下
    2023-12-12
  • spring-boot2.7.8添加swagger的案例詳解

    spring-boot2.7.8添加swagger的案例詳解

    這篇文章主要介紹了spring-boot2.7.8添加swagger的案例詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解

    Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解

    這篇文章主要介紹了Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 基于SpringBoot和Vue3的博客平臺(tái)發(fā)布、編輯、刪除文章功能實(shí)現(xiàn)

    基于SpringBoot和Vue3的博客平臺(tái)發(fā)布、編輯、刪除文章功能實(shí)現(xiàn)

    在上一個(gè)教程中,我們已經(jīng)實(shí)現(xiàn)了基于Spring?Boot和Vue3的用戶注冊(cè)與登錄功能。本教程將繼續(xù)引導(dǎo)您實(shí)現(xiàn)博客平臺(tái)的發(fā)布、編輯、刪除文章功能,需要的朋友參考一下
    2023-04-04
  • Java實(shí)現(xiàn)插入排序

    Java實(shí)現(xiàn)插入排序

    這篇文章主要介紹了Java實(shí)現(xiàn)插入排序,把一列數(shù)組按從小到大或從大到小排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • IDEA安裝部署Alibaba Cloud Toolkit的實(shí)現(xiàn)步驟

    IDEA安裝部署Alibaba Cloud Toolkit的實(shí)現(xiàn)步驟

    Alibaba Cloud Toolkit是阿里云針對(duì)IDE平臺(tái)為開發(fā)者提供的一款插件,本文主要介紹了IDEA安裝部署Alibaba Cloud Toolkit的實(shí)現(xiàn)步驟,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • java 實(shí)現(xiàn)取int型的第二個(gè)字節(jié)的數(shù)

    java 實(shí)現(xiàn)取int型的第二個(gè)字節(jié)的數(shù)

    這篇文章主要介紹了java 實(shí)現(xiàn)取int型的第二個(gè)字節(jié)的數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Spring spel表達(dá)式使用方法示例

    Spring spel表達(dá)式使用方法示例

    這篇文章主要介紹了Spring spel表達(dá)式使用方法示例,通過一些實(shí)例向大家展示了spel表達(dá)式的用法,需要的朋友可以了解下。
    2017-09-09
  • java使用PageInfo的list通用分頁處理demo

    java使用PageInfo的list通用分頁處理demo

    這篇文章主要為大家介紹了java使用PageInfo的list通用分頁處理demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2023-12-12
  • java Beanutils.copyProperties( )用法詳解

    java Beanutils.copyProperties( )用法詳解

    這篇文章主要介紹了java Beanutils.copyProperties( )用法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05

最新評(píng)論