最近在网上查看用MapReduce实现的Kmeans算法,例子是不错,http://blog.csdn.net/jshayzf/article/details/22739063

但注释太少了,而且参数太多,如果新手学习的话不太好理解。所以自己按照个人的理解写了一个简单的例子并添加了详细的注释。

大致的步骤是:

1,Map每读取一条数据就与中心做对比,求出该条记录对应的中心,然后以中心的ID为Key,该条数据为value将数据输出。

2,利用reduce的归并功能将相同的Key归并到一起,集中与该Key对应的数据,再求出这些数据的平均值,输出平均值。

3,对比reduce求出的平均值与原来的中心,如果不相同,这将清空原中心的数据文件,将reduce的结果写到中心文件中。(中心的值存在一个HDFS的文件中)

删掉reduce的输出目录以便下次输出。

继续运行任务。

4,对比reduce求出的平均值与原来的中心,如果相同。则删掉reduce的输出目录,运行一个没有reduce的任务将中心ID与值对应输出。

 package MyKmeans;

 import java.io.IOException;
import java.util.ArrayList; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text; import java.util.Arrays;
import java.util.Iterator; import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class MapReduce { public static class Map extends Mapper<LongWritable, Text, IntWritable, Text>{ //中心集合
ArrayList<ArrayList<Double>> centers = null;
//用k个中心
int k = 0; //读取中心
protected void setup(Context context) throws IOException,
InterruptedException {
centers = Utils.getCentersFromHDFS(context.getConfiguration().get("centersPath"),false);
k = centers.size();
} /**
* 1.每次读取一条要分类的条记录与中心做对比,归类到对应的中心
* 2.以中心ID为key,中心包含的记录为value输出(例如: 1 0.2 。 1为聚类中心的ID,0.2为靠近聚类中心的某个值)
*/
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
//读取一行数据
ArrayList<Double> fileds = Utils.textToArray(value);
int sizeOfFileds = fileds.size(); double minDistance = 99999999;
int centerIndex = 0; //依次取出k个中心点与当前读取的记录做计算
for(int i=0;i<k;i++){
double currentDistance = 0;
for(int j=0;j<sizeOfFileds;j++){
double centerPoint = Math.abs(centers.get(i).get(j));
double filed = Math.abs(fileds.get(j));
currentDistance += Math.pow((centerPoint - filed) / (centerPoint + filed), 2);
}
//循环找出距离该记录最接近的中心点的ID
if(currentDistance<minDistance){
minDistance = currentDistance;
centerIndex = i;
}
}
//以中心点为Key 将记录原样输出
context.write(new IntWritable(centerIndex+1), value);
} } //利用reduce的归并功能以中心为Key将记录归并到一起
public static class Reduce extends Reducer<IntWritable, Text, Text, Text>{ /**
* 1.Key为聚类中心的ID value为该中心的记录集合
* 2.计数所有记录元素的平均值,求出新的中心
*/
protected void reduce(IntWritable key, Iterable<Text> value,Context context)
throws IOException, InterruptedException {
ArrayList<ArrayList<Double>> filedsList = new ArrayList<ArrayList<Double>>(); //依次读取记录集,每行为一个ArrayList<Double>
for(Iterator<Text> it =value.iterator();it.hasNext();){
ArrayList<Double> tempList = Utils.textToArray(it.next());
filedsList.add(tempList);
} //计算新的中心
//每行的元素个数
int filedSize = filedsList.get(0).size();
double[] avg = new double[filedSize];
for(int i=0;i<filedSize;i++){
//求没列的平均值
double sum = 0;
int size = filedsList.size();
for(int j=0;j<size;j++){
sum += filedsList.get(j).get(i);
}
avg[i] = sum / size;
}
context.write(new Text("") , new Text(Arrays.toString(avg).replace("[", "").replace("]", "")));
} } @SuppressWarnings("deprecation")
public static void run(String centerPath,String dataPath,String newCenterPath,boolean runReduce) throws IOException, ClassNotFoundException, InterruptedException{ Configuration conf = new Configuration();
conf.set("centersPath", centerPath); Job job = new Job(conf, "mykmeans");
job.setJarByClass(MapReduce.class); job.setMapperClass(Map.class); job.setMapOutputKeyClass(IntWritable.class);
job.setMapOutputValueClass(Text.class); if(runReduce){
//最后依次输出不许要reduce
job.setReducerClass(Reduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
} FileInputFormat.addInputPath(job, new Path(dataPath)); FileOutputFormat.setOutputPath(job, new Path(newCenterPath)); System.out.println(job.waitForCompletion(true));
} public static void main(String[] args) throws ClassNotFoundException, IOException, InterruptedException {
String centerPath = "hdfs://localhost:9000/input/centers.txt";
String dataPath = "hdfs://localhost:9000/input/wine.txt";
String newCenterPath = "hdfs://localhost:9000/out/kmean"; int count = 0; while(true){
run(centerPath,dataPath,newCenterPath,true);
System.out.println(" 第 " + ++count + " 次计算 ");
if(Utils.compareCenters(centerPath,newCenterPath )){
run(centerPath,dataPath,newCenterPath,false);
break;
}
}
} }
 package MyKmeans;

 import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.util.LineReader; public class Utils { //读取中心文件的数据
public static ArrayList<ArrayList<Double>> getCentersFromHDFS(String centersPath,boolean isDirectory) throws IOException{ ArrayList<ArrayList<Double>> result = new ArrayList<ArrayList<Double>>(); Path path = new Path(centersPath); Configuration conf = new Configuration(); FileSystem fileSystem = path.getFileSystem(conf); if(isDirectory){
FileStatus[] listFile = fileSystem.listStatus(path);
for (int i = 0; i < listFile.length; i++) {
result.addAll(getCentersFromHDFS(listFile[i].getPath().toString(),false));
}
return result;
} FSDataInputStream fsis = fileSystem.open(path);
LineReader lineReader = new LineReader(fsis, conf); Text line = new Text(); while(lineReader.readLine(line) > 0){
ArrayList<Double> tempList = textToArray(line);
result.add(tempList);
}
lineReader.close();
return result;
} //删掉文件
public static void deletePath(String pathStr) throws IOException{
Configuration conf = new Configuration();
Path path = new Path(pathStr);
FileSystem hdfs = path.getFileSystem(conf);
hdfs.delete(path ,true);
} public static ArrayList<Double> textToArray(Text text){
ArrayList<Double> list = new ArrayList<Double>();
String[] fileds = text.toString().split(",");
for(int i=0;i<fileds.length;i++){
list.add(Double.parseDouble(fileds[i]));
}
return list;
} public static boolean compareCenters(String centerPath,String newPath) throws IOException{ List<ArrayList<Double>> oldCenters = Utils.getCentersFromHDFS(centerPath,false);
List<ArrayList<Double>> newCenters = Utils.getCentersFromHDFS(newPath,true); int size = oldCenters.size();
int fildSize = oldCenters.get(0).size();
double distance = 0;
for(int i=0;i<size;i++){
for(int j=0;j<fildSize;j++){
double t1 = Math.abs(oldCenters.get(i).get(j));
double t2 = Math.abs(newCenters.get(i).get(j));
distance += Math.pow((t1 - t2) / (t1 + t2), 2);
}
} if(distance == 0.0){
//删掉新的中心文件以便最后依次归类输出
Utils.deletePath(newPath);
return true;
}else{
//先清空中心文件,将新的中心文件复制到中心文件中,再删掉中心文件 Configuration conf = new Configuration();
Path outPath = new Path(centerPath);
FileSystem fileSystem = outPath.getFileSystem(conf); FSDataOutputStream overWrite = fileSystem.create(outPath,true);
overWrite.writeChars("");
overWrite.close(); Path inPath = new Path(newPath);
FileStatus[] listFiles = fileSystem.listStatus(inPath);
for (int i = 0; i < listFiles.length; i++) {
FSDataOutputStream out = fileSystem.create(outPath);
FSDataInputStream in = fileSystem.open(listFiles[i].getPath());
IOUtils.copyBytes(in, out, 4096, true);
}
//删掉新的中心文件以便第二次任务运行输出
Utils.deletePath(newPath);
} return false;
}
}

数据集   http://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data

运行结果可以与http://blog.csdn.net/jshayzf/article/details/22739063的结果做对比(前提是初始的中心相同)

MapReduce Kmeans聚类算法的更多相关文章

  1. Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解

        Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解 在Hadoop分布式环境下实现K-Means聚类算法的伪代码如下: 输入:参数0--存储样本数据的文本文件inpu ...

  2. K-Means 聚类算法

    K-Means 概念定义: K-Means 是一种基于距离的排他的聚类划分方法. 上面的 K-Means 描述中包含了几个概念: 聚类(Clustering):K-Means 是一种聚类分析(Clus ...

  3. k-means聚类算法python实现

    K-means聚类算法 算法优缺点: 优点:容易实现缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢使用数据类型:数值型数据 算法思想 k-means算法实际上就是通过计算不同样本间的距离来判断他 ...

  4. K-Means 聚类算法原理分析与代码实现

    前言 在前面的文章中,涉及到的机器学习算法均为监督学习算法. 所谓监督学习,就是有训练过程的学习.再确切点,就是有 "分类标签集" 的学习. 现在开始,将进入到非监督学习领域.从经 ...

  5. Kmeans聚类算法原理与实现

    Kmeans聚类算法 1 Kmeans聚类算法的基本原理 K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一.K-means算法的基本思想是:以空间中k个点为中心进行聚类,对 ...

  6. 机器学习六--K-means聚类算法

    机器学习六--K-means聚类算法 想想常见的分类算法有决策树.Logistic回归.SVM.贝叶斯等.分类作为一种监督学习方法,要求必须事先明确知道各个类别的信息,并且断言所有待分类项都有一个类别 ...

  7. 转载: scikit-learn学习之K-means聚类算法与 Mini Batch K-Means算法

    版权声明:<—— 本文为作者呕心沥血打造,若要转载,请注明出处@http://blog.csdn.net/gamer_gyt <—— 目录(?)[+] ================== ...

  8. 沙湖王 | 用Scipy实现K-means聚类算法

    沙湖王 | 用Scipy实现K-means聚类算法 用Scipy实现K-means聚类算法

  9. Matlab中K-means聚类算法的使用(K-均值聚类)

    K-means聚类算法采用的是将N*P的矩阵X划分为K个类,使得类内对象之间的距离最大,而类之间的距离最小. 使用方法:Idx=Kmeans(X,K)[Idx,C]=Kmeans(X,K) [Idx, ...

随机推荐

  1. Haxe数据类型

    以下是Haxe里面的一些数据类型 基本类型 空特性 类 枚举 匿名结构 方法 动态 抽象 1. 基本类型Bool, Float, Int 2. 空特性由于Haxe可以被编译为各种不同的target,不 ...

  2. PCL—低层次视觉—点云滤波(初步处理)

    点云滤波的概念 点云滤波是点云处理的基本步骤,也是进行 high level 三维图像处理之前必须要进行的预处理.其作用类似于信号处理中的滤波,但实现手段却和信号处理不一样.我认为原因有以下几个方面: ...

  3. iosUITextField属性

    @property UITextField *caption; caption = [[UITextField alloc] initWithFrame:CGRectMake(, self.frame ...

  4. NDK(22)JNI编程如何避免常见缺陷

    转自 : http://www.ibm.com/developerworks/cn/java/j-jni/index.html 避免常见缺陷 假设您编写了一些新 JNI 代码,或者继承了别处的某些 J ...

  5. yeoman开始项目

    使用 yeoman 构建项目之前,你需要安装这两个环境:node,ruby. 为什么需要使用node?因为我们需要使用grunt自动化工具,而grunt工具则是依赖node. 为什么需要使用ruby? ...

  6. JAVA的核心概念:接口(interface)

    JAVA的核心概念:接口(interface) 接口与类属于同一层次,实际上,接口是一种特殊的抽象类. 如:    interface IA{ }  public interface: 公开接口  与 ...

  7. JAVA将Excel中的报表导出为图片格式(一)问题背景

    如题所示,先抛出一个问题,如何使用JAVA将Excel中的报表导出为图片格式? 首先说一下这个问题的背景,也就是为什么博主会碰到这个问题 随着微信,易信之流大行其道,企业内部的办公交流.绩效考评甚至考 ...

  8. iOS开发:告诉git不要跟踪UserInterfaceState.xcuserstate

    在xcode中使用git管理项目的技巧: 在多人协作开发的时候,每个开发者都会在项目中的某个目录生成一个 UserInterfaceState.xcuserstate 文件,这个文件大概每5s会刷新一 ...

  9. Azure SQL 数据库新服务级别现已正式发布

    T.K.Ranga Rengarajan   2014 年 9 月 10 日上午 11:00 我们很高兴地宣布,新的 SQL 数据库服务级被基本.标准和高级级别现已正式发布.这些服务级别中含有内置且可 ...

  10. CImage 获取图片RGB 、图片高和宽;

    1 CImage img , img1 ,imDest; 2 img1.Load( 图片路径); 3 img.Load( 图片路径); 4 为了防止图片失真,先处理一下在把图片显示出来 5 SetSt ...