NLP——Kmeans聚類演算法簡單實現
阿新 • • 發佈:2019-01-07
本例中主要是對二維點進行距離計算,開始得時候選取兩個心,最終聚為兩簇。
結束條件的判斷有很多種,這裡採用的是最簡單的:當兩個心不再變化了,則停止聚類。
內部距離和可以不需要計算,這裡輸出來做結果評估用。
public class Km_w2 { //初始化二維資料 /* public static double[] x = {1, 2, 1, -1, -3, -2}; public static double[] y = {1, 1, 3, 2, -4, -1}; public static int n = 6;//一共有6個點 */ public static double[] x = {1, 2, 1, -1, -3, -2, 2, -1, 2}; public static double[] y = {1, 1, 3, 2, -4, -1, -1, -1, -5}; public static int n = 9; //手選兩個點,這裡選擇下標為1和4的兩個點,k為2 public static int i1 = 0;//1,1 public static int i2 = 3;//-1,2 public static double x1 = x[i1], x2 = x[i2], y1 = y[i1], y2 = y[i2]; public static void main(String[] args) { int count = 1; while (true) { System.out.println("-------------這是第"+count+"次聚類----------------"); // 定義兩個簇 List<Integer> c1 = new ArrayList<>(); List<Integer> c2 = new ArrayList<>(); Map<Integer, Double> dist = new HashMap<>();// 用來記錄所有點到它所屬心的距離 for (int i = 0; i < n; i++) { //篩選當前遍歷的點既不是心1,也不是心2 if (!(x[i] == x1 && y[i] == y1) && !(x[i] == x2 && y[i] == y2)) { double d1 = distance(x[i], y[i], x1, y1); double d2 = distance(x[i], y[i], x2, y2); System.out.println("點"+i+"("+x[i]+","+y[i]+")距離心1("+x1+","+y1+")和心2("+x2+","+y2+")的距離分別為:"+d1+","+d2); // 如果說這個點離簇1更加近,將它放到c1中,否則相反,並且在map中記錄下距離 if (d1 <= d2) { c1.add(i); dist.put(i, d1); } else { c2.add(i); dist.put(i, d2); } } } // 算距離和 System.out.println("當前1簇內部距離和為:"+distSum(c1, dist)); System.out.println("當前2簇內部距離和為:"+distSum(c2, dist)); //因為心在計算後有可能是存在的點,有可能是不存在的點。 //如果是存在的點則放到所屬的簇中 i1 = isExist(x1, y1); if(i1 != -1) { c1.add(i1); System.out.println("1簇添加了心1:"+x1+","+y1); } i2 = isExist(x2, y2); if(i2 != -1) { c2.add(i2); System.out.println("2簇添加了心2:"+x2+","+y2); } //備份並重新計算心的座標 double t_x1 = x1; double t_x2 = x2; double t_y1 = y1; double t_y2 = y2; x1 = avg(c1, x); y1 = avg(c1, y); x2 = avg(c2, x); y2 = avg(c2, y); System.out.println("新的心1為"+x1+","+y1); System.out.println("新的心2為"+x2+","+y2); System.out.println("簇1的內容為"+c1.toString()); System.out.println("簇2的內容為"+c2.toString()); //如果心不再更新 if(t_x1==x1 && t_x2==x2 && t_y1==y1 && t_y2==y2) { System.out.println("======================================="); System.out.println("聚類結束,結果為:"); System.out.println("簇1:"+c1.toString()); System.out.println("簇2:"+c2.toString()); break; } count++; } } //該方法用於計算2維兩點距離 public static double distance(double x1, double y1, double x2, double y2) { return Math.sqrt(Math.pow(x1 - x2, 2)+Math.pow(y1 - y2, 2)); } //該方法用於計算一個簇中所有點到心的距離和 public static double distSum(List<Integer> c, Map<Integer, Double> dist) { double sum = 0; for (int i : c) { sum += dist.get(i); } return sum; } //該方法用於計算簇中x或y的平均值 public static double avg(List<Integer> c, double[] xory) { int sum = 0; for (int i : c) { sum += xory[i]; } return sum/(c.size()*1.0); } //該方法用於判斷心是否是一個存在於資料集的點 public static int isExist(double a, double b) { for(int i = 0; i < x.length; i++) { if(a == x[i] && b == y[i]) { return i; } } return -1; } }