k均值聚类算法考试例题_K均值聚类算法的Java版实现代码示例

本文详细介绍了K均值聚类算法的工作原理,包括聚类的概念和k均值算法的步骤。提供了一个Java代码示例,展示如何实现K均值聚类算法,并附带测试案例,结果显示聚类效果基本符合预期。
摘要由CSDN通过智能技术生成

1.简介

K均值聚类算法是先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。

2.什么是聚类

聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为无监督学习。

3.什么是k均值聚类

k均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的。给定一个数据点集合和需要的聚类数目k,k由用户指定,k均值算法根据某个距离函数反复把数据分入k个聚类中。

4.实现

Java代码如下:

package org.algorithm;

import java.util.ArrayList;

import java.util.Random;

/**

* K均值聚类算法

*/

public class Kmeans {

private int k;

// 分成多少簇

private int m;

// 迭代次数

private int dataSetLength;

// 数据集元素个数,即数据集的长度

private ArrayList dataSet;

// 数据集链表

private ArrayList center;

// 中心链表

private ArrayList> cluster;

// 簇

private ArrayList jc;

// 误差平方和,k越接近dataSetLength,误差越小

private Random random;

/**

* 设置需分组的原始数据集

*

* @param dataSet

*/

public void setDataSet(ArrayList dataSet) {

this.dataSet = dataSet;

}

/**

* 获取结果分组

*

* @return 结果集

*/

public ArrayList> getCluster() {

return cluster;

}

/**

* 构造函数,传入需要分成的簇数量

*

* @param k

* 簇数量,若k<=0时,设置为1,若k大于数据源的长度时,置为数据源的长度

*/

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();

}

/**

* 如果调用者未初始化数据集,则采用内部测试数据集

*/

private void initDataSet() {

dataSet = new ArrayList();

// 其中{6,3}是一样的,所以长度为15的数据集分成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]);

}

}

/**

* 初始化中心数据链表,分成多少簇就有多少个中心点

*

* @return 中心点集

*/

private ArrayList initCenters() {

ArrayList center = new ArrayList();

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循环导致j无法加1

// for(j=0;j

// {

// if(temp==randoms[j]);

// {

// break;

// }

// }

while (j < i) {

if (temp == randoms[j]) {

break;

}

j++;

}

if (j == i) {

flag = false;

}

}

randoms[i] = temp;

}

// 测试随机数生成情况

// for(int i=0;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 一个分为k簇的空数据的簇集合

*/

private ArrayList> initCluster() {

ArrayList> cluster = new ArrayList>();

for (int i = 0; i < k; i++) {

cluster.add(new ArrayList());

}

return cluster;

}

/**

* 计算两个点之间的距离

*

* @param element

* 点1

* @param center

* 点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

* 距离数组

* @return 最小距离在距离数组中的位置

*/

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) // 如果相等,随机返回一个位置

{

if (random.nextint(10) < 5) {

minLocation = i;

}

}

}

return minLocation;

}

/**

* 核心,将当前元素放到最小距离中心相关的簇中

*/

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));

// 核心,将当前元素放到最小距离中心相关的簇中

}

}

/**

* 求两点误差平方的方法

*

* @param element

* 点1

* @param center

* 点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;

}

/**

* 计算误差平方和准则函数方法

*/

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);

}

/**

* 设置新的簇中心方法

*/

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];

}

// 设置一个平均值

newCenter[0] = newCenter[0] / n;

newCenter[1] = newCenter[1] / n;

center.set(i, newCenter);

}

}

}

/**

* 打印数据,测试用

*

* @param dataArray

* 数据集

* @param dataArrayName

* 数据集名称

*/

public void printDataArray(ArrayList 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");

// 循环分组,直到误差不变为止

while (true) {

clusterSet();

// for(int i=0;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);//输出迭代次数

}

/**

* 执行算法

*/

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.说明:

具体代码是从网上找的,根据自己的理解加了注释和进行部分修改,若注释有误还望指正

6.测试

package org.test;

import java.util.ArrayList;

import org.algorithm.Kmeans;

public class KmeansTest {

public static void main(String[] args)

{

//初始化一个Kmean对象,将k置为10

Kmeans k=new Kmeans(10);

ArrayList dataSet=new ArrayList();

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});

//设置原始数据集

k.setDataSet(dataSet);

//执行算法

k.execute();

//得到聚类结果

ArrayList> cluster=k.getCluster();

//查看结果

for (int i=0;i

{

k.printDataArray(cluster.get(i), "cluster["+i+"]");

}

}

}

总结:测试代码已经通过。并对聚类的结果进行了查看,结果基本上符合要求。至于有没有更精确的算法有待发现。具体的实践还有待挖掘

总结

以上就是本文关于K均值聚类算法的Java版实现代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题。如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

【摘要】 目前,对于聚类问题的研究普遍存在于社会生活中的各个领域,如模式识别、图像处理、机器学习和统计学等。关于对生活中各种各样的数据的聚类分类问题已经成为众多学者的研究热题之一。聚类和分类的区别在于,聚类没有任何先验知识可循,要通过数据自身的特点,将数据自动的划分到不同的类别中。聚类的基本形式定义为“在已给的数据集合中寻找数据点集的同类集合。每一个集合叫做一个类,并确定了一个区域,在区域中对象的密度高于其他区域中的密度。”聚类方法有很多种,其中最简单的形式便是划分式聚类,划分式聚类试图将给定的数据集合分割成不相交的子集,使具体的聚类准则是最优的。实际中应用最广泛的准则是聚类误差平方和准则,即对于每一个点都计算它到相应的聚类中心点的平方距离,并对数据集合上的所有点的距离进行求和。一种最流行的基于最小聚类误差平法和的聚类方法是K-均值算法。然而,K-均值算法是一个局部搜索的算法,它存在一些严重的不足,比如K值需要预先确定、聚类结果的好坏依赖于初始点的选取。为了解决这些问题,这个领域的研究者开发了很多其他的一些技术,试图基于全局最优化的方法来解决聚类问题(比如模拟退火算法、遗传算法等)。然而这些技术并没有得到广泛的认可,在许多实际应用中应用最多的还是反复利用K-均值算法。K-均值算法是一种基于划分的聚类算法,它通过不断的迭代来进行聚类,当算法收敛到一个结束条件时就终止迭代过程,输出聚类结果。由于其算法思想简便,又容易实现对大规模数据的聚类,因此K-均值算法已成为一种最常用的聚类算法之一K-均值算法能找到关于聚类误差的局部的最优解,是一个能应用在许多聚类问题上的快速迭代算法。它是一种以点为基础的聚类算法,以随机选取的初始点为聚类中心,迭代地改变聚类中心来使聚类误差最小化。这种方法最主要的不足就是对于初始聚类中心点位置的选取敏感。因此,为了得到近似最优解,初始聚类中心的位置必须安排的有差异。本文就K-均值聚类算法的聚类结果依赖于初始中心,而且经常收敛于局部最优解,而非全局最优解,以及聚类类别数K需要事先给定这两大缺憾展开研究。提出了分别解决这两个问题的算法各一个首先,本文将Hae-Sang等人的快速K-中心点算法确定初始中心点的思想应用于Aristidis Likas的全局K-均值聚类算法中下一个簇的初始中心选择上,提出一种改进的全局K-均值聚类算法,试图寻找一个周围样本点分布比较密集,且距离现有簇的中心都较远的样本点,将其作为下一个簇的最佳初始中心。通过对UCI机器学习数据库数据及人工随机模拟数据的测试,证明本文算法与Aristidis Likas的全局K-均值聚类算法和快速全局K-均值聚类算法比,在不影响聚类误差平方和的前提下,聚类时间更短,具有更好的性能。同时,本文介绍了自组织特征映射网络(Self-Organizing Feature Map, SOFM)的相关内容,SOFM网络是将多维数据映射到低维规则网格中,可以有效的进行大规模的数据挖掘,其特点是速度快,但是分类的精度不高。而K-均值聚类算法,是一种通过不断迭代调整聚类质心的算法,其特点是精度高,主要用于中小数据集的分类,但是聚类速度比较慢。因此,本文在分析了基于自组织特征映射网络聚类的学习过程,权系数自组织过程中邻域函数,以及学习步长的一般取值问题后,给出了基于自组织特征映射网络聚类实现的具体算法,将自组织特征网络与K-均值聚类算法相结合,提出了一种基于自组织映射网络的聚类方法,来实现对输入模式进行聚类,实现K-均值聚类算法的聚类类别数的自动确定。同时通过实验进行仿真实现,证明该算法的有效性。 还原 【Abstract】 Clustering is a fundamental problem that frequently arises in a great variety of fields such as pattern recognition, image processing, machine learning and statistics. In general, clustering is defined as the problem of finding homogeneous groups of samples in a given data set. Each of these groups is called a cluster and can be defined as a region in which the density of exemplars is locally higher than in other regions.The simplest form of clustering is partition clustering w
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值