大数据挖掘实践——K-Means聚类算法

大数据挖掘实践

K-Means聚类算法

引言:

有n个数据D={X1,X2,…,Xn},我们想把这些数据分成K个类。这个问题的关键在于K为多大时分类是合适的,并且我们也不好选择一个好的初始点。所以我们在这里引入距离的概念(以欧式距离为例)。我们想找到K个中心,数据离哪些中心近我们就将其定义为哪一类,同时我们的K个中心能够使这个分类最合理也就是每个点到其中心的距离的和最小。提炼为:找K个中心,数据属于距离离其最近的中心一类,这K个中心能使所有数据距离其中心的距离和最小。

算法介绍:

L-Means又叫做K均值算法,是一个已知聚类类别数的划分算法。它是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标。K表示聚簇中心的个数,代表数据中存在多少数据簇。K-Means可以高效地处理大数据集,它的输入自然是数据集和类别数,聚类结果是划分为k类的k个数据集。K-Means算法类似于KNN算法,都用到了距离矢量度量。

算法框架:
(1)、设定数字k,从n个初始数据中随机的设置k个点为聚类中心点。
(2)、针对n个点的每个数据点,遍历计算到k个聚类中心点的距离,最后按照离哪个中心点最近,就划分到那个类别中。
(3)、对每个已经划分好类别的n个点,对同个类别的点求均值,作为此类别新的中心点。
(4)、循环(2),(3)直到最终中心点收敛。
大数据挖掘实践——K-Means聚类算法_第1张图片
(流程图)

数据描述:
训练数据集
创建一个input.txt文件,随机构造几组数据,输入到txt文件中
大数据挖掘实践——K-Means聚类算法_第2张图片

实践过程
代码实现:
创建主实现类:

package KMeans;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;

/**
 * k均值算法工具类
 *
 * @author wxy
 *
 */
public class KMeansTool {
   // 输入数据文件地址
   private String filePath;
   // 分类类别个数
   private int classNum;
   // 类名称
   private ArrayList<String> classNames;
   // 聚类坐标点
   private ArrayList<Point> classPoints;
   // 所有的数据左边点
   private ArrayList<Point> totalPoints;

   public KMeansTool(String filePath, int classNum) {
      this.filePath = filePath;
      this.classNum = classNum;
      readDataFile();
   }

   /**
    * 从文件中读取数据
    */
   private void readDataFile() {
      File file = new File(filePath);
      ArrayList<String[]> dataArray = new ArrayList<String[]>();

      try {
         BufferedReader in = new BufferedReader(new FileReader(file));
         String str;
         String[] tempArray;
         while ((str = in.readLine()) != null) {
            tempArray = str.split(" ");
            dataArray.add(tempArray);
         }
         in.close();
      } catch (IOException e) {
         e.getStackTrace();
      }

      classPoints = new ArrayList<>();
      totalPoints = new ArrayList<>();
      classNames = new ArrayList<>();
      for (int i = 0, j = 1; i < dataArray.size(); i++) {
         if (j <= classNum) {
            classPoints.add(new Point(dataArray.get(i)[0],
                  dataArray.get(i)[1], j + ""));
            classNames.add(i + "");
            j++;
         }
         totalPoints
               .add(new Point(dataArray.get(i)[0], dataArray.get(i)[1]));
      }
   }

   /**
    * K均值聚类算法实现
    */
   public void kMeansClustering() {
      double tempX = 0;
      double tempY = 0;
      int count = 0;
      double error = Integer.MAX_VALUE;
      Point temp;

      while (error > 0.01 * classNum) {
         for (Point p1 : totalPoints) {
            // 将所有的测试坐标点就近分类
            for (Point p2 : classPoints) {
               p2.computerDistance(p1);
            }
            Collections.sort(classPoints);

            // 取出p1离类坐标点最近的那个点
            p1.setClassName(classPoints.get(0).getClassName());
         }

         error = 0;
         // 按照均值重新划分聚类中心点
         for (Point p1 : classPoints) {
            count = 0;
            tempX = 0;
            tempY = 0;
            for (Point p : totalPoints) {
               if (p.getClassName().equals(p1.getClassName())) {
                  count++;
                  tempX += p.getX();
                  tempY += p.getY();
               }
            }
            tempX /= count;
            tempY /= count;

            error += Math.abs((tempX - p1.getX()));
            error += Math.abs((tempY - p1.getY()));
            // 计算均值
            p1.setX(tempX);
            p1.setY(tempY);

         }

         for (int i = 0; i < classPoints.size(); i++) {
            temp = classPoints.get(i);
            System.out.println(MessageFormat.format("聚类中心点{0},x={1},y={2}",
                  (i + 1), temp.getX(), temp.getY()));
         }
         System.out.println("----------");
      }

      System.out.println("结果值收敛");
      for (int i = 0; i < classPoints.size(); i++) {
         temp = classPoints.get(i);
         System.out.println(MessageFormat.format("聚类中心点{0},x={1},y={2}",
               (i + 1), temp.getX(), temp.getY()));
      }

   }

}

坐标点类:

package KMeans;

/**
 * 坐标点类
 *
 * @author wxy
 *
 */
public class Point implements Comparable<Point>{
   // 坐标点横坐标
   private double x;
   // 坐标点纵坐标
   private double y;
   //以此点作为聚类中心的类的类名称
   private String className;
   // 坐标点之间的欧式距离
   private Double distance;

   public Point(double x, double y) {
      this.x = x;
      this.y = y;
   }

   public Point(String x, String y) {
      this.x = Double.parseDouble(x);
      this.y = Double.parseDouble(y);
   }

   public Point(String x, String y, String className) {
      this.x = Double.parseDouble(x);
      this.y = Double.parseDouble(y);
      this.className = className;
   }


   public void computerDistance(Point p) {
      if (p == null) {
         return;
      }

      this.distance = (this.x - p.x) * (this.x - p.x) + (this.y - p.y)
            * (this.y - p.y);
   }

   public double getX() {
      return x;
   }

   public void setX(double x) {
      this.x = x;
   }

   public double getY() {
      return y;
   }

   public void setY(double y) {
      this.y = y;
   }

   public String getClassName() {
      return className;
   }

   public void setClassName(String className) {
      this.className = className;
   }

   public double getDistance() {
      return distance;
   }

   public void setDistance(double distance) {
      this.distance = distance;
   }

   @Override
   public int compareTo(Point o) {
      // TODO Auto-generated method stub
      return this.distance.compareTo(o.distance);
   }

}

调用类:

package KMeans;


public class Client {
   public static void main(String[] args){
      String filePath = "D:\\dashuju\\src\\KMeans\\input.txt";
      int classNum = 3;
      
      KMeansTool tool = new KMeansTool(filePath, classNum);
      tool.kMeansClustering();
   }
}

测试结果:
大数据挖掘实践——K-Means聚类算法_第3张图片

总结
通过本次实现K-Means聚类算法的实验,使我更深刻的了解了K-Means算法。这次作业我是用自己比较擅长的Java语言完成的,最终的成果展示可能并没有其他语言那么形象,但我还是能从中收获很多。
Ⅰ.首先K-Means算法最大的优点就是简单易懂,没有涉及那些复杂的数据结构;
Ⅱ.当然K-Means算法也有它的缺点。K的值不好确定,而且由于计算是迭代的,所以当数据规模较大时,会消耗大量的内存和时间;
Ⅲ.虽然只是冰山一角,但通过这次实验以及对大数据这门课程的学习,领略到了大数据这个“流行事物”的魅力,丰富了自己的知识储备。

你可能感兴趣的:(大数据挖掘实践——K-Means聚类算法)