zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    LeetCode Find Duplicate File in System
    LeetCode 681. Next Closest Time
    LeetCode 678. Valid Parenthesis String
    LeetCode 616. Add Bold Tag in String
    LeetCode 639. Decode Ways II
    LeetCode 536. Construct Binary Tree from String
    LeetCode 539. Minimum Time Difference
    LeetCode 635. Design Log Storage System
    LeetCode Split Concatenated Strings
    LeetCode 696. Count Binary Substrings
  • 原文地址:https://www.cnblogs.com/jamesf/p/4751564.html
Copyright © 2011-2022 走看看