K-Means算法
系统采用vm下ubuntu16.04
一、 实验内容与要求
在Eclipse环境下编写实现K-means算法。
二、 实验数据与目标
1、实验数据
来源于http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data。实验数据文件名为iris.txt(鸢尾花数据集),数据大小为4.6KB。数据的格式下图所示,每行代表一个数据点对象,数值为对象属性值,字符串为类型。总共分为3类,每类50条。
DFS Locations
|--hadoopTest
|--(1)
|--user(1)
|--hk(1)
|--KMeans_in(1)
|--iris.txt
2、实验目标
输入簇中心个数3和迭代次数I,用MapReduce来实现Kmeans算法,对实验数据进行分类。并查看同簇中,不同类型数据的数量。理想结果为分了3簇,每簇中对象类型基本相同。
三、 实现思路:
1、实现可行性分析:
在进行K-Means聚类中,在处理每一个数据点时,只需要知道各个cluster的中心信息(簇ID, 簇中点个数,簇中心点对象属性),不需要知道关于其他数据点的任何信息。数据中所有点对象不互相影响,因此可以进行Hadoop并行处理。
2、MapReduce并行化KMeans算法设计思路:
(1)将所有的点对象数据分布到不同的MapReduce节点上,每个节点只对自己的数据进行计算。
(2)每个Map节点能够读取上一次迭代生成的cluster中心点信息,并判断自己的各个数据点应该属于哪一个cluster。
(3)Reduce节点累加属于某个cluster的每个数据点,计算出新的cluster中心点,输出到指定序列号文件中,作为下一次迭代的输入。
Map用来找到每个点对象所属的簇ID,Reduce 将相同簇ID点对象数据合并生成新簇对象
3、代码实现流程思路:
(1)初始化:根据传入K值,在源数据中随机选择K个点对象作为初始的簇中心,生成簇对象(簇ID, 簇中点个数,簇中心点对象属性)存入输出文件中。
(2)迭代:遍历源数据点对象,将其中的每个点对象与上一次输出文件中的簇对象记录进行比较根据最短欧式距离分配到不同的簇中,并计算生成下次迭代用到的新簇对象,存入对应索引输出文件中,以便下次迭代使用。
(3)输出最终结果:遍历源数据点对象,根据最后一次迭代输出的簇对象来分配到不同的簇,然后输出分类结果。
四、 代码实现
(1)Point类
package edu.hk.kmeans;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.hadoop.io.Writable;
public class Point implements Writable {
//属性特征值
ArrayList<Double> values;
String type;
public Point() {
values = new ArrayList<Double>();
}
public Point(ArrayList<Double> tempValues) {
values =tempValues;
}
//读取数据,每一行的数据都是一个对象的属性值
public Point(String line) {
String[] valueString = line.split(",");
values = new ArrayList<Double>();
for (int i = 0; i < valueString.length-1; i++) {
values.add(Double.parseDouble(valueString[i]));
}
type = valueString[valueString.length-1];
}
public void setValues(ArrayList<Double> tempValue) {
values = tempValue;
}
public ArrayList<Double> getValues() {
return values;
}
//将属性中转换为string值输出
public String toString() {
String s = new String();
for (int i = 0; i < values.size() ; i++) {
s += (values.get(i) + ",");
}
s +=type;
return s;
}
@Override
public void write(DataOutput out) throws IOException {
// TODO Auto-generated method stub
out.writeInt(values.size());
for (int i = 0; i < values.size(); i++) {
out.writeDouble(values.get(i));
}
}
@Override
public void readFields(DataInput in) throws IOException {
// TODO Auto-generated method stub
int size = 0;
values = new ArrayList<Double>();
if ((size = in.readInt()) != 0) {
for (int i = 0; i < size; i++) {
values.add(in.readDouble());
}
}
}
}
(2)Cluster类
package edu.hk.kmeans;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable;
//簇
public class Cluster implements Writable{
//簇Id
private int clusterID;
//簇中点数
private long numOfPoints;
//簇中心
private Point center;
public Cluster(){
this.setClusterID(-1);
this.setNumOfPoints(0);
this.setCenter(new Point());
}
public Cluster(int clusterID,Point center){
this.setClusterID(clusterID);
this.setNumOfPoints(0);
this.setCenter(center);
}
public Cluster(String line){
String[] value = line.split(",",3);
clusterID = Integer.parseInt(value[0]);
numOfPoints = Long.parseLong(value[1]);
center = new Point(value[2]);
}
public String toString(){
String result = String.valueOf(clusterID) + ","
+ String.valueOf(numOfPoints) + "," + center.toString();
return result;
}
public int getClusterID() {
return clusterID;
}
public void setClusterID(int clusterID) {
this.clusterID = clusterID;
}
public long getNumOfPoints() {
return numOfPoints;
}
public void setNumOfPoints(long numOfPoints) {
thi