Kmeans算法参考记录
来源:互联网 发布:疯狂联盟座龙升级数据 编辑:程序博客网 时间:2024/06/05 23:08
[-]
- 基本Kmeans算法1
- 注意问题
- 1K如何确定
- 与层次聚类结合2
- 稳定性方法3
- 系统演化方法3
- 使用canopy算法进行初始划分4
- 2初始质心的选取
- 3距离的度量
- 4质心的计算
- 5算法停止条件
- 6空聚类的处理
- 1K如何确定
- 适用范围及缺陷
- 实现
1.基本Kmeans算法[1]
时间复杂度:O(tKmn),其中,t为迭代次数,K为簇的数目,m为记录数,n为维数空间复杂度:O((m+K)n),其中,K为簇的数目,m为记录数,n为维数
2.注意问题
(1)K如何确定
kmenas算法首先选择K个初始质心,其中K是用户指定的参数,即所期望的簇的个数。这样做的前提是我们已经知道数据集中包含多少个簇,但很多情况下,我们并不知道数据的分布情况,实际上聚类就是我们发现数据分布的一种手段,这就陷入了鸡和蛋的矛盾。如何有效的确定K值,这里大致提供几种方法,若各位有更好的方法,欢迎探讨。
1.与层次聚类结合[2]
经常会产生较好的聚类结果的一个有趣策略是,首先采用层次凝聚算法决定结果粗的数目,并找到一个初始聚类,然后用迭代重定位来改进该聚类。
2.稳定性方法[3]
稳定性方法对一个数据集进行2次重采样产生2个数据子集,再用相同的聚类算法对2个数据子集进行聚类,产生2个具有k个聚类的聚类结果,计算2个聚类结果的相似度的分布情况。2个聚类结果具有高的相似度说明k个聚类反映了稳定的聚类结构,其相似度可以用来估计聚类个数。采用次方法试探多个k,找到合适的k值。
3.系统演化方法[3]
系统演化方法将一个数据集视为伪热力学系统,当数据集被划分为K个聚类时称系统处于状态K。系统由初始状态K=1出发,经过分裂过程和合并过程,系统将演化到它的稳定平衡状态Ki,其所对应的聚类结构决定了最优类数Ki。系统演化方法能提供关于所有聚类之间的相对边界距离或可分程度,它适用于明显分离的聚类结构和轻微重叠的聚类结构。
4.使用canopy算法进行初始划分[4]
基于Canopy Method的聚类算法将聚类过程分为两个阶段
Stage1、聚类最耗费计算的地方是计算对象相似性的时候,Canopy Method在第一阶段选择简单、计算代价较低的方法计算对象相似性,将相似的对象放在一个子集中,这个子集被叫做Canopy ,通过一系列计算得到若干Canopy,Canopy之间可以是重叠的,但不会存在某个对象不属于任何Canopy的情况,可以把这一阶段看做数据预处理;
Stage2、在各个Canopy 内使用传统的聚类方法(如K-means),不属于同一Canopy 的对象之间不进行相似性计算。
从这个方法起码可以看出两点好处:首先,Canopy 不要太大且Canopy 之间重叠的不要太多的话会大大减少后续需要计算相似性的对象的个数;其次,类似于K-means这样的聚类方法是需要人为指出K的值的,通过Stage1得到的Canopy 个数完全可以作为这个K值,一定程度上减少了选择K的盲目性。
其他方法如贝叶斯信息准则方法(BIC)可参看文献[5]。
(2)初始质心的选取
(3)距离的度量
(4)质心的计算
(5)算法停止条件
(6)空聚类的处理
3.适用范围及缺陷
package com.kmeans.fjsh.algorithm;import java.util.ArrayList; import java.util.Random; /** * K均值聚类算法 */ 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(); 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; 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<i;++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<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 一个分为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)); // 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<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(); } }
package com.kmeans.fjsh.algorithm;import java.util.ArrayList; public class KmeansTest { public static void main(String[] args) { //初始化一个Kmean对象,将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}); //设置原始数据集 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+"]"); } } }
- Kmeans算法参考记录
- kmeans算法及python代码参考
- kmeans算法及python代码参考
- Kmeans 记录
- KMeans 算法
- Kmeans算法
- kmeans算法
- Kmeans算法
- Kmeans算法
- kmeans++算法
- Kmeans算法
- [算法3]Kmeans算法
- Kmeans、Kmeans++和KNN算法比较
- Kmeans、Kmeans++和KNN算法比较
- Kmeans、Kmeans++和KNN算法比较
- Kmeans、Kmeans++和KNN算法比较
- Kmeans、Kmeans++和KNN算法比较
- Kmeans、Kmeans++和KNN算法比较
- iOS开发:将图片存到本地
- Linux 文件权限 umask
- 我安装了最新版的wamp,用composer提示PHP版本低
- ionic 列表选项的移动和移除
- Windows10+Ubuntu双系统安装
- Kmeans算法参考记录
- Tomcat 6.0 安装与启动
- Spring中的AOP功能
- android studio 初步认识
- Activity生命周期
- grpc java helloworld 简单demo实现
- 记忆
- mac 如何显示隐藏文件和.点开头文件?
- RocketMQ常用命令