• k-means聚类JAVA实例


    《mahout in action》第六章。

    datafile/cluster/simple_k-means.txt数据集如下:

    1 1
    2 1
    1 2
    2 2
    3 3
    8 8
    8 9
    9 8
    9 9

    1. k-means聚类算法原理


    1、从D中随机取k个元素,作为k个簇的各自的中心。


    2、分别计算剩下的元素到k个簇中心的相异度,将这些元素分别划归到相异度最低的簇。


    3、根据聚类结果,重新计算k个簇各自的中心,计算方法是取簇中所有元素各自维度的算术平均数。


    4、将D中全部元素按照新的中心重新聚类。


    5、重复第4步,直到聚类结果不再变化。


    6、将结果输出。

    2. 举例说明


    2.1 从D中随机取k个元素,作为k个簇的各自的中心。

    private final static Integer K=2; //选K=2,也就是估算有两个簇。
    下面选1 1,2,1两个点。
    C0:1 1
    C1:2 1

    2.2 分别计算剩下的元素到k个簇中心的相异度,将这些元素分别划归到相异度最低的簇。

    结果为:
    C0 : 1 1
    C0:的点为:1.0,2.0
    C1:  2 1
    C1:的点为:2.0,2.0
    C1:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0



    2.3 根据2.2的聚类结果,重新计算k个簇各自的中心,计算方法是取簇中所有元素各自维度的算术平均数。

    采取欧区距离公式。
    C0 新的簇心为:1.0,1.5
    C1 新的簇心为:5.857142857142857,5.714285714285714

    2.4 将D中全部元素按照新的中心重新聚类。

    第2次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0


    2.5  重复第4步,直到聚类结果不再变化。

    当距离小于某个值的时候,就认为聚类已经聚类了,不需要再迭代,这里的值选0.001
    private final static Double converge=0.001;

    ------------------------------------------------
    C0的簇心为:1.6666666666666667,1.75
    C1的簇心为:7.971428571428572,7.942857142857143
    各个簇心移动中最小的距离为,move=0.7120003121097943
    第3次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.777777777777778,1.7916666666666667
    C1的簇心为:8.394285714285715,8.388571428571428
    各个簇心移动中最小的距离为,move=0.11866671868496578
    第4次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.7962962962962965,1.7986111111111114
    C1的簇心为:8.478857142857143,8.477714285714285
    各个簇心移动中最小的距离为,move=0.019777786447494432
    第5次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.799382716049383,1.7997685185185184
    C1的簇心为:8.495771428571429,8.495542857142857
    各个簇心移动中最小的距离为,move=0.003296297741248916
    第6次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.7998971193415638,1.7999614197530864
    C1的簇心为:8.499154285714287,8.499108571428572
    各个簇心移动中最小的距离为,move=5.49382956874724E-4

    3. JAVA实现

    package mysequence.machineleaning.clustering.kmeans;
    
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Vector;
    
    import mysequence.machineleaning.clustering.canopy.Point;
    
    public class MyKmeans {
    
    	static Vector<Point>  li=new Vector<Point>();
    	//static List<Point>  li=new ArrayList<Point>();
    	static List<Vector<Point>> list=new ArrayList<Vector<Point>>(); //每次迭代保存结果,一个vector代表一个簇
    	private final static Integer K=2; //选K=2,也就是估算有两个簇。
    	private final static Double converge=0.001; //当距离小于某个值的时候,就认为聚类已经聚类了,不需要再迭代,这里的值选0.001	
    	
    	//读取数据
    	public static final void readF1() throws IOException {      
    		String filePath="datafile/cluster/simple_k-means.txt";
    		BufferedReader br = new BufferedReader(new InputStreamReader(
            new FileInputStream(filePath)));
            for (String line = br.readLine(); line != null; line = br.readLine()) {
                if(line.length()==0||"".equals(line))continue;
            	String[] str=line.split(" ");               
                Point p0=new Point();
        		p0.setX(Double.valueOf(str[0]));
        		p0.setY(Double.valueOf(str[1]));
        		li.add(p0);
                //System.out.println(line);               
            }
            br.close();
        }
    	  //math.sqrt(double n)
        //扩展下,如果要给m开n次方就用java.lang.StrictMath.pow(m,1.0/n);
    	//采用欧氏距离
    	public static  Double DistanceMeasure(Point p1,Point p2){
    		
    		Double tmp=StrictMath.pow(p2.getX()-p1.getX(), 2)+StrictMath.pow(p2.getY()-p1.getY(), 2);
    		return Math.sqrt(tmp);
    	}
    	
    	//计算新的簇心
    	public static Double CalCentroid(){
    		System.out.println("------------------------------------------------");
    		Double movedist=Double.MAX_VALUE;
    		for(int i=0;i<list.size();i++){
    			Vector<Point> subli=list.get(i);
    			Point po=new Point();
    			Double sumX=0.0;
    			Double sumY=0.0;
    			Double Clusterlen=Double.valueOf(subli.size());
    			for(int j=0;j<Clusterlen;j++){
    				Point nextp=subli.get(j);
    				sumX=sumX+nextp.getX();
    				sumY=sumY+nextp.getY();
    			}
    			po.setX(sumX/Clusterlen);
    			po.setY(sumY/Clusterlen);
    			//新的点与旧点之间的距离
    			Double dist=DistanceMeasure(subli.get(0),po);
    			//在多个簇心移动的过程中,返回移动距离最小的值
    			if(dist<movedist)movedist=dist;
    			list.get(i).clear();
    			list.get(i).add(po);
    			System.out.println("C"+i+"的簇心为:"+po.getX()+","+po.getY());
    		}
    		String test="ll";
    		return movedist;
    	}
    	//本次的簇心
    	//下一次移动的簇心
    	
    	private static Double move=Double.MAX_VALUE;//移动距离
    	//不断地迭代,直到收敛
    	public static void RecursionKluster(){
    		for(int times=2;move>converge;times++){
    			System.out.println("第"+times+"次迭代");
    			//默认每一个list里的Vector第0个元素是质心
    			for(int i=0;i<li.size();i++){
    				Point p=new Point();
    				 p=li.get(i);
    				int index = -1;
    				
    	            double neardist = Double.MAX_VALUE;
    				for(int k=0;k<K;k++){
    					Point centre=list.get(k).get(0);
    					double currentdist=DistanceMeasure(p,centre);
    					if(currentdist<neardist){
    						neardist=currentdist;
    						index=k;
    					}
    				}
    				
    				System.out.println("C"+index+":的点为:"+p.getX()+","+p.getY());
    				list.get(index).add(p);
    				
    			}
    			//重新计算簇心,并返回移动的距离,最小的那个距离
    			
    			move=CalCentroid();
    			System.out.println("各个簇心移动中最小的距离为,move="+move);
    		}
    	}
    	
    	public static void Kluster(){
    		
    		for(int k=0;k<K;k++){
    			Vector<Point> vect=new Vector<Point>();
    			Point p=new Point();
    			p=li.get(k);
    			vect.add(p);
    			list.add(vect);
    		}
    		System.out.println("第1次迭代");
    		//默认每一个list里的Vector第0个元素是质心
    		for(int i=K;i<li.size();i++){
    			Point p=new Point();
    			 p=li.get(i);
    			int index = -1;
    			
                double neardist = Double.MAX_VALUE;
    			for(int k=0;k<K;k++){
    				Point centre=list.get(k).get(0);
    				double currentdist=DistanceMeasure(p,centre);
    				if(currentdist<neardist){
    					neardist=currentdist;
    					index=k;
    				}
    			}
    			
    			System.out.println("C"+index+":的点为:"+p.getX()+","+p.getY());
    			list.get(index).add(p);
    			
    		}
    		
    	}
    	
    	public static void main(String[] args) throws IOException {
    		// TODO Auto-generated method stub
    		//读取数据
    		readF1();
    		//第一次迭代
    		Kluster();
    		//第一次迭代后计算簇心
    		CalCentroid();
    		//不断迭代,直到收敛
    		RecursionKluster();
    	}
    
    }
    

    4.运行结果:

    C0:1 1
    C1:2 1
    第1次迭代
    C0:的点为:1.0,2.0
    C1:的点为:2.0,2.0
    C1:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.0,1.5
    C1的簇心为:5.857142857142857,5.714285714285714
    第2次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.6666666666666667,1.75
    C1的簇心为:7.971428571428572,7.942857142857143
    各个簇心移动中最小的距离为,move=0.7120003121097943
    第3次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.777777777777778,1.7916666666666667
    C1的簇心为:8.394285714285715,8.388571428571428
    各个簇心移动中最小的距离为,move=0.11866671868496578
    第4次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.7962962962962965,1.7986111111111114
    C1的簇心为:8.478857142857143,8.477714285714285
    各个簇心移动中最小的距离为,move=0.019777786447494432
    第5次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.799382716049383,1.7997685185185184
    C1的簇心为:8.495771428571429,8.495542857142857
    各个簇心移动中最小的距离为,move=0.003296297741248916
    第6次迭代
    C0:的点为:1.0,1.0
    C0:的点为:2.0,1.0
    C0:的点为:1.0,2.0
    C0:的点为:2.0,2.0
    C0:的点为:3.0,3.0
    C1:的点为:8.0,8.0
    C1:的点为:8.0,9.0
    C1:的点为:9.0,8.0
    C1:的点为:9.0,9.0
    ------------------------------------------------
    C0的簇心为:1.7998971193415638,1.7999614197530864
    C1的簇心为:8.499154285714287,8.499108571428572
    各个簇心移动中最小的距离为,move=5.49382956874724E-4

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Hive学习小记-(4)带复杂集合类型及指定多分隔符hive建表
    nowcoder-shell篇(grep、awk、sed为主)
    剑指offer02-替换空格
    剑指offer67-剪绳子**
    爬虫5-Scrapy爬虫架构
    爬虫4-网站结构分析
    爬虫3-python爬取非结构化数据下载到本地
    项目创建
    项目框架搭建
    项目表结构
  • 原文地址:https://www.cnblogs.com/jamesf/p/4751564.html
Copyright © 2020-2023  润新知