`

K-均值算法

 
阅读更多

总是有废话要先说~~

二妹原创,转载请注明出处,大家讨论~

上次面试,写自我评价的缺点,我写的比较胖~~然后拿offer了,人啊 就是要看得见的实诚!

 

----------------------------------------我是废话分割线 -------------------------------------------------------------

 

web上大量的数据,希望对这些数据进行聚类,而事先并不知道该怎么聚类,k-均值算法则是将大数据聚为k类。

关键要素:

1:用户事先要确定K的值,这个可能需要大量的测试优化k值。k值代表将数据聚为k类,那么将会产生k个簇的质心(均值所在的位置)。

2:聚类的的数据节点之间必须是可以计算平均值。K均值的思想就是某一堆数据都在一个均值的附近,那么将这一堆数据划为一簇。

3:适用于球状分布的数据。例如如果数据是环形分布的,直观上应该将同一环形的数据归为一类,而用k均值则可能分为扇形簇。

4:初始的质心选择得不同,则得到的聚类也会不同。

例如如下图,当k为3的时候,下面红黄蓝是正确的分类,使用k均值算法可以正确的分类第一类,而第二类则会出现错误。

 

以Person为例,现在有一堆人的集合,将他们分为三类,按年龄相近来分类。

 

Person对象,相当于集合中的节点。

package com.zyp.learn.datamining.algorithm;

public class Person {
	private int age;
	private String name;
	
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

 

算法实现类:

    package com.zyp.learn.datamining.algorithm;  
      
    import java.util.ArrayList;  
    import java.util.HashMap;  
    import java.util.HashSet;  
    import java.util.List;  
    import java.util.Map;  
    import java.util.Set;  
      
      
    /** 
     * K均值算法 
     * @author 卓二妹 2012/10/31 
     * 
     */  
    public class KAverageAlgorithm {  
          
        public static void main(String[] args){  
            //生成集合,年龄随机生成0-99的数字  
//            Set<Person> personSet= initSet(5);  
    
            //生成固定值集合,便于调试        	 
               Set<Person> personSet= initSet();  
              
            System.out.print("集合元素:");  
            for(Person p : personSet){  
                System.out.print(p.getAge()+" ");  
            }  
            System.out.println();  
            // 调用无监督学习的k均值算法,将这50人按年龄分为3类,如老、中、青  
            Person[] centerArray = cluster(3,personSet);   
              
            System.out.print("质心:");  
            for(Person center : centerArray){  
                System.out.print(center.getAge()+" ");  
            }  
              
            //标记元素所属质心  
            Map<String,List> map = new HashMap();  
              
            //集合中的某个元素所属的质心,加到该质心对应的数组上  
            for(Person p: personSet){  
                int index = nearestIndex(centerArray,p);//p属于centerArray[index]质心  
                List<Person> lst = map.get(centerArray[index].getAge()+"");  
                if(lst==null){  
                    lst = new ArrayList();  
                    map.put(centerArray[index].getAge()+"",lst);  
                }  
                lst.add(p);  
            }  
              
            System.out.println("\n质心包含的元素:");  
            for(Person center : centerArray){  
                System.out.print(center.getAge()+" :");  
                List<Person> lst = map.get(center.getAge()+"");  
                if(lst!=null){  
                    for(Person p : lst){  
                        System.out.print(p.getAge()+" ");  
                    }  
                }  
                System.out.println("\n");  
            }  
        }  
          
        /** 
         * 将person集合分类,按照person的年龄维度来分类。 
         * 分为k个年龄段,而每个年龄段是事前并不知道。 
         * 用k-均值算法的硬盘版本,只需要遍历一次全集。 
         * @param k:簇的数量 
         * @param personSet:要划分簇的全集 
         * @return 质心的数组 
         */  
        public static Person[] cluster(int k,final Set<Person> personSet){  
            Person[] centerArray = new Person[k];   
            //由于集合是无序的,因此在集合中选前k个点做初始的质心(任意k个点)  
            int i = 0;  
            for(Person p:personSet){  
                centerArray[i++] = p;  
                if(i==k){  
                    break;  
                }  
            }  
              
            //进行一遍执行的调整,本次调整中,改变了所属簇的节点的数量为chanedPointNum  
            int chanedPointNum = -1;  
            //直到没有任何person所属簇都不再变化后,结束分类  
            boolean isExit = false;
            while(isExit){  
            	Person[] newCenterArray = adjustCenteroid(centerArray,personSet);  
            	isExit = exit(newCenterArray,centerArray,personSet);
            }  
              
            return centerArray;  
        }  
          
        /** 
         * 进行一遍质心的调整 
         * @param centerArray 质心数组 
         * @param personSet 全集 
         * return 返回本轮调整质心,改变了所属簇的Person的个数 
         */  
        public static Person[] adjustCenteroid(final Person[] centerArray,final Set<Person> personSet){  
            int changedPointNum = 0;//本次调整质心,改变了所属的簇的节点的个数  
            int oldIndex = -1;  
            int newIndex = -1;  
            int k = centerArray.length;  
            //distArray[i]代表该划划分到第i类的年龄的总和  
            int[] distArray = new int[k];  
              
            //numberArray[i]代表划分到第i类的年龄有多少个  
            int[] numberArray = new int[k];  
              
            //待返回的新质心
            Person[] newCenterArray  = new Person[k];
            
            //将数组元素初始化为0  
            initArray(distArray);  
            initArray(numberArray);  
              
            for(Person tempPerson:personSet){  
                //计算该tempPerson到centerArray的第index质心最近  
                int index = nearestIndex(centerArray,tempPerson);  
                //则该tempPerson被划为第index质心代表的簇中  
                distArray[index] = distArray[index] + tempPerson.getAge();  
                numberArray[index] ++;  
            }  
              
            //已将每个元素分到k个质心中,重新计算每个簇的均值,得到新的质心  
            for(int index = 0; index<k;index++){  
            	newCenterArray[index] = new Person("",distArray[index]/numberArray[index]);
            }  
            return newCenterArray;  
        }  
        
        /**
         * 质心调整的退出标准 
         * @param centerArray当前的质心
         * @param oldCenterArray 调整前的质心
         * @param personSet 数据集合
         * @return 数据集合的簇在质心调整前后无变化,则返回true
         */
        public static boolean exit(final Person[] centerArray,final Person[] oldCenterArray,final Set<Person> personSet){
        	boolean isExit = false;
        	int changedPointNum = 0;
            
            //遍历person集合,看质心调整后,person的所属簇是否改变  
            for(Person tempPerson:personSet){  
                int newIndex = nearestIndex(centerArray,tempPerson);  
                int oldIndex = nearestIndex(oldCenterArray,tempPerson);  
                if(oldIndex!=newIndex){  
                    changedPointNum++;  
                }
            } 
            if(changedPointNum==0){
            	isExit = true;
            }
        	return isExit;
        }  
        public static void initArray(int array[]){  
            for(int i = 0;i<array.length;i++){  
                array[i] = 0;  
            }  
        }  
          
        public static int nearestIndex(final Person[] centerArray,final Person tempPerson){  
            int minIndex = 0;//与该点距离最近的质心的index  
            int minValue = 100;//与最近的质心的距离  
              
            for(int i = 0;i<centerArray.length;i++){  
                int centerAge = centerArray[i].getAge();  
                int temp = Math.abs(tempPerson.getAge()-centerAge);//数据点的年龄与质心距离  
                if(temp<=minValue){  
                    minValue = temp;//  
                    minIndex = i;  
                }  
            }  
            return minIndex;  
        }  
          
      
          
        /** 
         * 初始化集合中的数据 
         * @param count:需要生成的集合的元素个数 
         * @return 
         */  
        public static Set<Person> initSet(int count){  
            Set<Person> set = new HashSet();  
    //      System.out.print("初始集合:");  
            for(int i=0;i<count;i++){  
                String name = "person"+i;  
                //随即生成0--99的人的年龄  
                int age = (int)(Math.random()*100);  
    //          System.out.print(age+" ");  
                set.add(new Person(name,age));  
            }  
            System.out.println();  
            return set;  
        }  
          
        /** 
         * 初始化集合中的数据,指定一些出错的数据,便于调试 
         * @return 
         */  
        public static Set<Person> initSet(){  
            Set<Person> set = new HashSet();  
            set.add(new Person("", 69));
            set.add(new Person("", 30));
            set.add(new Person("", 75));
            set.add(new Person("", 12));
            set.add(new Person("", 14));
            return set;  
        } 
    }  
 

运行一下main方法,随机生成5个人,按年龄分为3类,打印结果如下:


集合元素:75 69 14 12 30
质心:75 69 14
质心包含的元素:
75 :75

69 :69

14 :14 12 30

 

二天空了再来解释算法,敬请期待~

 

分享到:
评论

相关推荐

    K-均值算法的高斯计分布

    k-均值算法的高斯计分布随机聚类的划分,用vc编程的,希望能帮助大家学习。

    新的K-均值算法最佳聚类数确定方法

    新的K-均值算法最佳聚类数确定方法,对均值聚类算法有极大地优化

    论文研究-基于样本空间分布密度的初始聚类中心优化K-均值算法.pdf

    针对传统K-均值聚类算法对初始聚类中心敏感、现有初始聚类中心优化算法缺乏客观性,提出一种基于样本空间分布密度的初始聚类中心优化K-均值算法。该算法利用数据集样本的空间分布信息定义数据对象的密度,并根据整个...

    K-均值聚类算法研究

    由于其算法思想简便,又容易实现对大规模数据的聚类,因此K-均值算法已成为一种最常用的聚类算法之一K-均值算法能找到关于聚类误差的局部的最优解,是一个能应用在许多聚类问题上的快速迭代算法。它是一种以点为基础的...

    改进的k-均值算法在聚类分析中的应用

    介绍了在聚类中广泛应用的经典k-均值算法,并针对其易受随机选择初始聚类中心和孤立点的影响的不足,给出了改进的k-均值算法。首先使用距离法移除孤立点,然后采用邻近吸收法对初始聚类中心的选择进行了改进。并做了...

    论文研究-启发式初始化独立的k-均值算法研究.pdf

    针对传统k-均值算法对初始聚类中心敏感的问题,提出了启发式初始化独立的k-均值算法。该算法引入prim算法选择k个初始聚类中心,且通过设置阈值参数θ,避免同一类中的多个数据对象同时作为初始聚类中心,否则将导致...

    Kmeans.docx K均值聚类算法实验报告

    K-Means算法是典型的基于距离的聚类算法,其中k代表类簇个数,means代表类簇内数据对象的均值(这种均值是一种对类簇中心的描述),因此,K-Means算法又称为k-均值算法。K-Means算法是一种基于划分的聚类算法,以...

    论文研究-基于半监督学习的K-均值聚类算法研究.pdf

    定义了一个欧氏距离和监督信息相混合的新的最近邻计算函数,从而将K-均值算法很好地应用于半监督聚类问题。针对K-均值算法初始质心敏感的缺陷,用粒子群算法的搜索空间模拟聚类的欧氏空间,迭代搜索找到较优的聚类质心...

    论文研究-基于密度期望和有效性指标的K-均值算法.pdf

    该方案可有效降低K-均值算法对初始中心点的依赖,从而获得较高的聚类质量。在此基础上,可进一步通过选择合适的聚类有效性指标Silhouette指标分析不同k值下的每次聚类结果,确定最佳聚类数,则可有效改善k值无法预先...

    论文研究-基于加权距离计算的自适应粗糙K-均值算法.pdf

    针对粗糙K-均值算法的执行效率较低和对数据对象的处理不准确问题,提出了基于加权距离计算的自适应粗糙K-均值算法。该算法在粗糙集理论应用的基础上修正数据集合的隶属度函数,结合属性约简方法,根据数据属性对聚类...

    k-均值算法的java实现

    NULL 博文链接:https://ghostfromheaven.iteye.com/blog/851516

    基于神经网络建模和K-均值算法的电池健康状态评估.pdf

    基于神经网络建模和K-均值算法的电池健康状态评估 本文旨在解决电池健康状态评估中的难题,通过对锂离子电池外特性的分析,采用BP神经网络算法对锂离子电池进行建模,并将其模型带入K-均值算法中,以实现对电池健康...

    基于核的K-均值聚类

    :将核学习方法的思想应用于K-均值聚类中,提出了一种核K-均值聚类算法,算法的主要思想是:首先将原空间中待聚类的样本经过 一个非线性映射,映射到一个高维的核空间中,突出各类样本之间的特征差异,然后在这个核...

    基于python实现K-均值算法与高斯混合模型及对应简单应用源码+项目说明+详细注释.zip

    基于python实现K-均值算法与高斯混合模型及对应简单应用源码+项目说明+详细注释.zip (K-均值算法与高斯混合模型) 1.采用两分量的高斯混合模型建模一组观测数据的分布,并用 EM 算法估计相关的 5 个参数,得到了...

    k-均值算法的具体实现

    采用k-均值算法解决多维空间中点的聚类分析问题,由于算法比较简单,这里不再赘述

    论文研究-一种基于数据场的K-均值算法.pdf

    针对K-均值算法在随机选取初始类中心时存在不足、对噪声和孤立点敏感、不适用于发现大小差别很大的类的问题,借鉴分子间的相互作用力模型,将文本模拟成数据场中的数据点,综合考虑文本间的相似度和相异度,提出一个...

    使用Weka进行K-近邻算法和K-均值算法的使用-附件资源

    使用Weka进行K-近邻算法和K-均值算法的使用-附件资源

Global site tag (gtag.js) - Google Analytics