二分Kmeans的java实现

刚刚研究了Kmeans。Kmeans是一种十分简单的聚类算法。但是他十分依赖于用户最初给定的k值。它无法发现任意形状和大小的簇,最适合于发现球状簇。他的时间复杂度为O(tkn)。kmeans算法有两个核心点:计算距离的公式&判断迭代停止的条件。一般距采用欧式距离等可以随意。判断迭代停止的条件可以有:

1) 每个簇的中心点不再变化则停止迭代

2)所有簇的点与这个簇的中心点的误差平方和(SSE)的所有簇的总和不再变化

3)设定人为的迭代次数,观察实验效果。


当初始簇心选择不好的时候聚类的效果会很差。所以后来又有一个人提出了二分k均值(bisectingkmeans),其核心思路是:将初始的一个簇一分为二计算出误差平方和最大的那个簇,对他进行再一次的二分。直至切分的簇的个数为k个停止。 其实质就是不断的对选中的簇做k=2的kmeans切分。

因为聚类的误差平方和能够衡量聚类性能,该值越小表示数据点月接近于它们的质心,聚类效果就越好。所以我们就需要对误差平方和最大的簇进行再一次的划分,因为误差平方和越大,表示该簇聚类越不好,越有可能是多个簇被当成一个簇了,所以我们首先需要对这个簇进行划分。


下面是代码,kmeans的原始代码来源于http://blog.csdn.net/cyxlzzs/article/details/7416491,我稍作了一些修改。


package org.algorithm;

import java.util.ArrayList;
import java.util.List;

/**
 * 二分k均值,实际上是对一个集合做多次的k=2的kmeans划分, 每次划分后会对sse值较大的簇再进行二分。 最终使得或分出来的簇的个数为k个则停止
 * 
 * 这里利用之前别人写好的一个kmeans的java实现作为基础类。
 * 
 * @author l0979365428
 * 
 */
public class BisectingKmeans {

	private int k;// 分成多少簇
	private List<float[]> dataSet;// 当前要被二分的簇
	private List<ClusterSet> cluster; // 簇

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		// 初始化一个Kmean对象,将k置为10
		BisectingKmeans bkm = new BisectingKmeans(5);
		// 初始化试验集
		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 });
		// 设置原始数据集
		bkm.setDataSet(dataSet);
		// 执行算法
		bkm.execute();
		// 得到聚类结果
		// ArrayList<ArrayList<float[]>> cluster = bkm.getCluster();
		// 查看结果
		// for (int i = 0; i < cluster.size(); i++) {
		// bkm.printDataArray(cluster.get(i), "cluster[" + i + "]");
		// }

	}

	public BisectingKmeans(int k) {
		// 比2还小有啥要划分的意义么
		if (k < 2) {
			k = 2;
		}
		this.k = k;

	}

	/**
	 * 设置需分组的原始数据集
	 * 
	 * @param dataSet
	 */

	public void setDataSet(ArrayList<float[]> dataSet) {
		this.dataSet = dataSet;
	}

	/**
	 * 执行算法
	 */
	public void execute() {
		long startTime = System.currentTimeMillis();
		System.out.println("BisectingKmeans begins");
		BisectingKmeans();
		long endTime = System.currentTimeMillis();
		System.out.println("BisectingKmeans running time="
				+ (endTime - startTime) + "ms");
		System.out.println("BisectingKmeans ends");
		System.out.println();
	}

	/**
	 * 初始化
	 */
	private void init() {

		int dataSetLength = dataSet.size();
		if (k > dataSetLength) {
			k = dataSetLength;
		}
	}

	/**
	 * 初始化簇集合
	 * 
	 * @return 一个分为k簇的空数据的簇集合
	 */
	private ArrayList<ArrayList<float[]>> initCluster() {
		ArrayList<ArrayList<float[]>> cluster = new ArrayList<ArrayList<float[]>>();
		for (int i = 0; i < k;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值