package com.bigdata.ml.cluster;
 
import java.util.ArrayList;
import java.util.Random;
 
/**
 * 聚类算法通常用于数据挖掘,将相似的数组进行聚簇
 * 
 * @author zouzhongfan
 *
 */
public class Kmeans {
    private int k;// 分成多少簇
    private int m;// 迭代次数
    private int dataSetLength;// 数据集元素个数,即数据集的长度
    private ArrayList<float[]> dataSet;// 数据集链表
    private ArrayList<float[]> center;// 中心链表
    private ArrayList<ArrayList<float[]>> cluster; // 簇
    private ArrayList<Float> jc;// 误差平方和,k越接近dataSetLength,误差越小
    private Random random;
 
    /**
     * 设置需分组的原始数据集
     * 
     * @param dataSet
     */
 
    public void setDataSet(ArrayList<float[]> dataSet) {
        this.dataSet = dataSet;
    }
 
    /**
     * 获取结果分组
     * 
     * @return 结果集
     */
    public ArrayList<ArrayList<float[]>> 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();
        // 若k大于数据源的长度时,置为数据源的长度
        if (k > dataSetLength) {
            k = dataSetLength;
        }
        center = initCenters();// 初始化中心
        cluster = initCluster();// 初始化簇集,分配内存,但元素为空
        jc = new ArrayList<Float>();// 初始化误差平方和
    }
 
    /**
     * 如果调用者未初始化数据集,则采用内部测试数据集
     */
    private void initDataSet() {
        dataSet = new ArrayList<float[]>();
        // 其中{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<float[]> initCenters() {
        ArrayList<float[]> center = new ArrayList<float[]>();
        int[] randoms = new int[k];
        boolean flag;
        // 生成k个互补相同的随机数
        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;
                while (j < i) {
                    if (temp == randoms[j]) {
                        break;
                    }
                    j++;
                }
                if (j == i) {
                    flag = false;
                }
            }
            randoms[i] = temp;
        }
        // 生成初始化中心链表
        for (int i = 0; i < k; i++) {
            center.add(dataSet.get(randoms[i]));
        }
        return center;
    }
 
    /**
     * 初始化簇集合
     * 
     * @return 一个分为k簇的空数据的簇集合
     */
    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;
    }
 
    /**
     * 计算两个点之间的距离(欧几里得距离)
     * 
     * @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));// 计算两个点之间的距离
            }
            int minLocation = minDistance(distance);
            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<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"); // 输出初始化中心
        // 循环分组,直到误差不变为止
        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);// 输出迭代次数
    }
 
    /**
     * 执行算法
     */
    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();
    }
 
    public static void main(String[] args) {
        // 初始化一个Kmean对象,将k置为3
        Kmeans k = new Kmeans(3);
        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 });
 
        // 设置原始数据集
        k.setDataSet(dataSet);
        // 执行算法
        k.execute();
        // 得到聚类结果
        ArrayList<ArrayList<float[]>> cluster = k.getCluster();
        // 查看结果
        for (int i = 0; i < cluster.size(); i++) {
            k.printDataArray(cluster.get(i), "cluster[" + i + "]");
        }
    }
}

以上代码介绍,就是把距离考的比较近的数组规划到一起,查看有哪些数组是距离比较考的最近的,方法和方式和一维数组聚类差不多。

K-means聚类分析算法(二)相关推荐

  1. k means聚类算法_一文读懂K-means聚类算法

    1.引言 什么是聚类?我们通常说,机器学习任务可以分为两类,一类是监督学习,一类是无监督学习.监督学习:训练集有明确标签,监督学习就是寻找问题(又称输入.特征.自变量)与标签(又称输出.目标.因变量) ...

  2. k means聚类算法_K-Means 聚类算法 20210108

    说到聚类,应先理解聚类和分类的区别 聚类和分类最大的不同在于:分类的目标是事先已知的,而聚类则不一样,聚类事先不知道目标变量是什么,类别没有像分类那样被预先定义出来. K-Means 聚类算法有很多种 ...

  3. OpenCV官方文档 理解k - means聚类

    理解k - means聚类 目标 在这一章中,我们将了解k - means聚类的概念,它是如何工作等. 理论 我们将这个处理是常用的一个例子. t恤尺寸问题 考虑一个公司要发布一个新模型的t恤. 显然 ...

  4. kmeans改进 matlab,基于距离函数的改进k―means 算法

    摘要:聚类算法在自然科学和和社会科学中都有很普遍的应用,而K-means算法是聚类算法中经典的划分方法之一.但如果数据集内相邻的簇之间离散度相差较大,或者是属性分布区间相差较大,则算法的聚类效果十分有 ...

  5. 机器学习笔记(3)——使用聚类分析算法对文本分类(分类数k未知)

    聚类分析是一种无监督机器学习(训练样本的标记信息是未知的)算法,它的目标是将相似的对象归到同一个簇中,将不相似的对象归到不同的簇中.如果要使用聚类分析算法对一堆文本分类,关键要解决这几个问题: 如何衡 ...

  6. k均值聚类算法(K Means)及其实战案例

    算法说明 K均值聚类算法其实就是根据距离来看属性,近朱者赤近墨者黑.其中K表示要聚类的数量,就是说样本要被划分成几个类别.而均值则是因为需要求得每个类别的中心点,比如一维样本的中心点一般就是求这些样本 ...

  7. SPSS聚类分析:K均值聚类分析

    SPSS聚类分析:K均值聚类分析 一.概念:(分析-分类-K均值聚类) 1.此过程使用可以处理大量个案的算法,根据选定的特征尝试对相对均一的个案组进行标识.不过,该算法要求您指定聚类的个数.如果知道, ...

  8. 文本聚类分析算法_常用的聚类分析算法综述

    聚类分析定义 所谓聚类就是按照事物的某些属性,把事物聚集成类,使类间的相似性尽可能小,类内相似性尽可能大.聚类是一个无监督的学习过程,它同分类的根本区别在于分类是需要事先知道所依据的数据特征,而聚类是 ...

  9. K-Means(K均值聚类算法)

    K-Means(K均值聚类算法) 1.前言 要学习聚类算法就要知道聚类学习算法是什么,为什么要学习聚类学习聚类学习算法,有什么用途,下面就简单的做一下介绍,并且详细的说明k-means均值聚类学习算法 ...

  10. 文本聚类分析算法_读书笔记(8)kmeans聚类算法及应用

    1.问题导入 假如有这样一种情况,在一天你想去某个城市旅游,这个城市里你想去的有70个地方,现在你只有每一个地方的地址,这个地址列表很长,有70个位置.事先肯定要做好攻略,你要把一些比较接近的地方放在 ...

最新文章

  1. 使用FileItem获取文件名时注意事项
  2. 为何说“内容+社交”是奥运发展化趋势?
  3. spark hive udf java_【填坑六】 spark-sql无法加载Hive UDF的jar
  4. python多进程模板
  5. python的翻译-用python实现百度翻译的示例代码
  6. 《庆余年》,腾讯视频、爱奇艺为“互联网黑产”背锅的一出戏
  7. JBOSS通过Apache负载均衡方法一:使用mod_jk
  8. 警示!国基金评审过程“打招呼”被通报批评,撤销已资助项目!
  9. ORA-27101 Shared memory realm does not exist 之解決 (转)
  10. CSDN 如何删除自己不用的分类(亲测有效!)
  11. ibatis 直接升格为 apache 一级项目了
  12. 2.GitLab 项目管理
  13. 集群服务器分布式iis_使用nginx实现分布式限流的方法
  14. 上传项目到GitLab
  15. 游戏ai人工智能_AI与游戏,第1部分:游戏如何推动了两门AI研究流派
  16. golang 实现http mock server
  17. 搭建自己的小程序服务器
  18. 混合算法(SA+TS)解决TSP问题——lua实现(Microcity)
  19. 算法学习之Markov Model(马尔可夫模型)
  20. docker容器日常管理(四)

热门文章

  1. 怎样查阅电脑最大能够扩充多大的内存
  2. 人如果没有愿望。。。。。。
  3. 20151227感知机(perceptron)
  4. php 实现 java com.sun.org.apache.xml.internal.security.utils.Base64 Byte数组加密
  5. LeetCode 3sum 问题
  6. 3-Spring Boot的数据访问
  7. html最小化位置不变,实现DIV相对于浏览器固定位置不变
  8. iso镜像添加软件包_超薄Docker容器-减少Docker镜像大小的指南
  9. python 伪多线程_Python实现简单多线程任务队列
  10. 佳能fax_l150如何打印_佳能faxl150说明书下载