Hadoop k-means 算法实现

经过昨天的准备工作,今天基本就可以编写整个k-means算法程序了。今天编写的时候遇到了一个问题,是combine操作时遇到的问题。除了这个问题基本都按照原来的思路进行。先说下我的思路吧。

准备工作:在上传数据文件到HDFS上之前,先应该产生一个中心文件,比如我的输入文件如下:

0.0	0.2	0.4
0.3	0.2	0.4
0.4	0.2	0.4
0.5	0.2	0.4
5.0	5.2	5.4
6.0	5.2	6.4
4.0	5.2	4.4
10.3	10.4	10.5
10.3	10.4	10.5
10.3	10.4	10.5
然后要产生中心文件,可以使用如下命令来操作:

(1)、获取文件的总行数:  wc data.txt 。可以得到文件的行数是 :10

(2)、因为我要分为三类,所以10/3=3,那么我取的行数就是1,3,6(这个行数可以自己选择,比如也可以直接去前三行 head -n 3 data.txt >centers.txt),然后使用如下命令:awk 'NR==1||NR==3||NR==6' data.txt > centers.txt,然后再把centers.txt上传到HDFS上就可以了。

(下面我使用的是前三行作为数据中心文件)

下面的程序中就不用设置要分 的类别和数据文件的维度数了,我在写这篇和前篇文章的时候参考了这篇文章:http://www.cnblogs.com/zhangchaoyang/articles/2634365.html,这篇里面要在代码中自己设置要分的类别以及数据文件的维度数。

下面是map-combine-reduce 操作:

map: map的setup()函数主要是读取中心文件把文件的中心点读入一个double[][]中,然后是map。数据转换为:

Text(包含数据的字符串)--》[index,DataPro(Text(包含数据文件的字符串),IntWritable(1))]

combine:

[index,DataPro(Text(包含数据文件的字符串),IntWritable(1))]-->[index,DataPro(Text(包含数据文件相同index的相加的结果的字符串),IntWritable(sum(1)))]

reduce: reduce的setup()函数主要是读取数据中心文件,然后取出其中的数据维度信息(在reduce操作中需要数组赋值需要知道数据维度),

[index,DataPro(Text(包含数据文件相同index的相加的结果的字符串),IntWritable(sum(1)))]--》[index,DataPro(Text(包含数据文件相同index的相加的结果的字符串),IntWritable(sum(1)))]--》[index,Text(相同index的数据相加的平均值)]

上面的是循环的过程,最后一个job任务是输出分类的结果。

下面贴代码:

KmeansDriver:

package org.fansy.date928;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
//import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class KmeansDriver {

	/**
	 *   k-means algorithm program  
	 */
	private static final String temp_path="hdfs://fansyPC:9000/user/fansy/date928/kmeans/temp_center/";
	private static final String dataPath="hdfs://fansyPC:9000/user/fansy/input/smallkmeansdata";
	private static final int iterTime=300;
	private static int iterNum=1;
	private static final double threadHold=0.01;
	
	private static Log log=LogFactory.getLog(KmeansDriver.class);
	
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		// TODO Auto-generated method stub
		Configuration conf=new Configuration();
		
		// set the centers data file
		Path centersFile=new Path("hdfs://fansyPC:9000/user/fansy/input/centers");
		DistributedCache.addCacheFile(centersFile.toUri(), conf);
		
		String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
	    if (otherArgs.length != 1) {
	      System.err.println("Usage: KmeansDriver <indatafile> ");
	      System.exit(2);
	    }
	    Job job = new Job(conf, "kmeans job 0");
	    job.setJarByClass(KmeansDriver.class);
	    job.setMapperClass(KmeansM.class);
	    job.setMapOutputKeyClass(IntWritable.class);
		job.setMapOutputValueClass(DataPro.class);
	    job.setNumReduceTasks(1);
	    job.setCombinerClass(KmeansC.class);
	    job.setReducerClass(KmeansR.class);
	    job.setOutputKeyClass(NullWritable.class);
	    job.setOutputValueClass(Text.class);    
	    FileInputFormat.addInputPath(job, new Path(dataPath));
	    FileOutputFormat.setOutputPath(job, new Path(temp_path+0+"/"));  
	    if(!job.waitForCompletion(true)){
	    	System.exit(1); // run error then exit
	    }
	    //  do iteration
	    boolean flag=true;
		while(flag&&iterNum<iterTime){
			Configuration conf1=new Configuration();
			
			// set the centers data file
			Path centersFile1=new Path(temp_path+(iterNum-1)+"/part-r-00000");  //  the new centers file
			DistributedCache.addCacheFile(centersFile1.toUri(), conf1);
			boolean iterflag=doIteration(conf1,iterNum);
			if(!iterflag){
				log.error("job fails");
				System.exit(1);
			}
			//  set the flag based on the old centers and the new centers
			
			Path oldCentersFile=new Path(temp_path+(iterNum-1)+"/part-r-00000");
			Path newCentersFile=new Path(temp_path+iterNum+"/part-r-00000");
			FileSystem fs1=FileSystem.get(oldCentersFile.toUri(),conf1);
			FileSystem fs2=FileSystem.get(oldCentersFile.toUri(),co
  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 54
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 54
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值