《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
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
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
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
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
版權聲明:本文為博主原創文章,未經博主允許不得轉載。