文章目录
1. K-Means的简单介绍
这个案例将实现一个简单的K-Means聚类算法。有必要先简单地介绍下K-Means的算法计算原理。
K-Means均值是一种迭代聚类算法,其工作原理如下:
- K-Means基于点数据集和一个初始的K值(簇个数)来计算;
- 在每次迭代中,算法计算每个数据点到每个簇中心的距离。每个点都被分配到离它最近的簇中心;
- 随后,将簇中的所有点的坐标平均值作为该簇的新的中心点;
- 被移动之后的簇中心将传递给下一轮迭代计算;
算法在固定次数的迭代后终止 (本案例采用的),或者簇中心不再怎么移动了,那么也可以终止计算。
2. 本案例说明
这个案例是在二维数据点数据集上实现的。输入文件是纯文本文件,文件格式必须要满足如下格式:
-
二维点数据集表示为两个由空白字符分隔的双精度值。数据点用换行符分隔。
例如:"1.2 2.3\n5.3 7.2\n"将代表两个点,分别是 (x=1.2, y=2.3)和(x=5.3, y=7.2)。 -
簇中心将由id和点坐标来呈现。
例如:"1 6.2 3.2\n2 2.9 5.7\n"将代表两个簇中心,分别是(id=1, x=6.2, y=3.2)和(id=2, x=2.9, y=5.7)。
通过本案例我们将主要学习如下知识:
- 批量迭代;
- 批量迭代中的广播变量;
- Java objects(POJOs)。
本案例主要是讲解一种应用思维方式,所以用来训练的原始数据不多。主要目的是为了展示效果。
3. 源码分析
3.1. 二维空间点坐标数据结构
public static class Point implements Serializable {
// x坐标,y坐标
public double x, y;
public Point() {
}
public Point(double x, double y) {
this.x = x;
this.y = y;
}
// 点坐标的加法器
public Point add(Point other) {
x += other.x;
y += other.y;
return this;
}
// 点坐标的除法器
public Point div(long val) {
x /= val;
y /= val;
return this;
}
// 计算点之间的欧式距离
public double euclideanDistance(Point other) {
return Math.sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y));
}
public void clear() {
x = y = 0.0;
}
@Override
public String toString() {
return x + " " + y;
}
}
3.2. 簇中心的数据结构
簇中心从物理角度看是称为质心。质心的数据结构代码定义如下:
/**
* 质心类, 基于点坐标和id.
*/
public static class Centroid extends Point {
public int id;
public Centroid() {
}
public Centroid(int id, double x, double y) {
super(x, y);
this.id = id;
}
public Centroid(int id, Point p) {
super(p.x, p.y);
this.id = id;
}
@Override
public String toString() {
return id + " " + super.toString();
}
}
簇中心(质心)的定义类,是基于Point的。其由一个质心Id和质心的位置坐标组成。
3.3. 默认数据集说明
如果主程序执行时没有指定输入的CSV文件路径,那么就读取默认数据。默认数据的定义如下:
package org.apache.flink.examples.java.clustering.util;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.examples.java.clustering.KMeans.Centroid;
import org.apache.flink.examples.java.clustering.KMeans.Point;
import java.util.LinkedList;
import java.util.List;
/**
* 提供用于K-Means示例程序的默认数据集。如果没有为程序提供参数,则使用默认数据集。
*
*/
public class KMeansData {
/**
* 簇中心(质心)数据
*/
public static final Object[][] CENTROIDS = new Object[][] {
new Object[] {
1, -31.85, -44.77},
new Object[]{
2, 35.16, 17.46},
new Object[]{
3, -5.16, 21.93},
new Object[]{
4, -24.06, 6.81}
};
/**
* 输入的点数据
*/
public static final Object[][] POINTS = new Object[][] {
new Object[] {
-14.22, -48.01},
new Object[] {
-22.78, 37.10},
new Object[] {
56.18, -42.99},
new Object[] {
35.04, 50.29},
new Object[] {
-9.53, -46.26},
new Object[] {
-34.35, 48.25}