你好,游客 登录
背景:
阅读新闻

mahout算法canopy源码分析之一:获得输入数据

[日期:2013-07-22] 来源:CSDN博客  作者: [字体: ]
对于canopy的输入数据需要的形式为序列文件,同时保证key:Text、value:VectorWritable。昨晚准备打算使用单纯的java程序搞定输入数据的准备,无奈老是会出点问题,昨晚的问题“找不到文件”暂时还没找到原因。

 

其实如果只是要获得输入数据那么,可以使用mahout官网提供的方法在得到了序列的*.txt文件后直接把mahout-distribution-0.7.zip解压拷贝到虚拟机,(在/etc/profile里面配置下hadoop_home变量)然后找到mahout_home/bin目录,执行 chmod +x mahout ,然后分别执行

 

[python] view plaincopy
 
  1. ./mahout seqdirectory -i <input> -o <output> 
[python] view plaincopy
 
  1. ./mahout seq2sparse -i <output>/chunk-0 -o <output-in

上面的<input>、<output>对应于自己的输入和输出;我所使用的数据并不是 Reuters dataset的全部数据,而只是前三个:reut2-000.sgm、reut2-001.sgm、reut2-002.sgm,这样的数据在经过ExtractReuters 后生成了3000个文件,然后经过seqdirectory合并成了一个2.41M的数据文件。seq2sparse有7个job,每个job负责自己的内容,这个暂时不加分析;最终的结果在<output-in>/tfidf-vectors里面,即为输入数据;

 

有了输入数据就可以直接跑程序了,首先不管程序是什么样子的,先跑出结果再说:

 

[java] view plaincopy
 
  1. package mahout.test.canopy; 
  2. import java.io.IOException; 
  3. import org.apache.hadoop.conf.Configuration; 
  4. import org.apache.hadoop.fs.Path; 
  5. import org.apache.mahout.clustering.canopy.CanopyDriver; 
  6. import org.apache.mahout.common.distance.DistanceMeasure; 
  7. import org.apache.mahout.common.distance.EuclideanDistanceMeasure; 
  8. public class CanopyTest { 
  9.     public static void main(String[] args) throws ClassNotFoundException, IOException, InterruptedException { 
  10.         Configuration conf =new Configuration(); 
  11.         conf.set("mapred.job.tracker""192.168.128.138:9001"); 
  12.         Path input=new Path("hdfs://hadoop:9000/user/hadoop/output/canopyvec/tfidf-vectors"); 
  13.         Path output=new Path("hdfs://hadoop:9000/user/hadoop/output/canopy-output"); 
  14.         DistanceMeasure measure=new EuclideanDistanceMeasure();   
  15.         CanopyDriver.buildClusters(conf, input, output, measure, 33.122.13false); 
  16.         System.out.println("job is done."); 
  17.     } 

最开始的时候我的t1、t2设置为3.1、2.1结果map出来的结果数是为零(这个暂时也不知道是代表什么意思),后来改为上面的结果可以看到map输出了509条记录,reduece输出3条记录(符合参数clusterFileter的设定值:3),最后的输出为:canopy-output/clusters-0-final/part-r-00000。

 

为了便于后面的观察,所以不使用上面的数据,而使用自己造的数据,造数据之前首先要知道输入数据的格式,那么使用下面的代码看下输入数据是什么:

 

[java] view plaincopy
 
  1. package mahout.test.utils; 
  2. import java.io.IOException; 
  3. import org.apache.hadoop.conf.Configuration; 
  4. import org.apache.hadoop.fs.Path; 
  5. import org.apache.hadoop.io.Text; 
  6. import org.apache.hadoop.mapreduce.Job; 
  7. import org.apache.hadoop.mapreduce.Mapper; 
  8. import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; 
  9. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 
  10. import org.apache.hadoop.util.ToolRunner; 
  11. import org.apache.mahout.common.AbstractJob; 
  12. import org.apache.mahout.math.Vector; 
  13. import org.apache.mahout.math.VectorWritable; 
  14. /** 
  15.  * 读取序列文件,输入Key:Text,Value:VectorWritable 
  16.  * @author fansy 
  17.  * @version 2013/7/21 11:32 
  18.  * 
  19.  */ 
  20. public class ReadTextVectorWritable extends AbstractJob { 
  21.     @Override 
  22.     public int run(String[] arg0) throws Exception { 
  23.         if(arg0.length!=6||(!"-i".equals(arg0[0])||(!"-o".equals(arg0[2]))||(!"-jt".equals(arg0[4])))){ 
  24.             System.err.println("参数不正确!"); 
  25.             System.out.println("Usage:"); 
  26.             System.out.println("-i <input> -o <output> -jt <jobtracker:port>"); 
  27.             System.exit(-1); 
  28.         }         
  29.         Configuration conf=new Configuration(); 
  30.         conf.set("mapred.job.tracker", arg0[5]); 
  31.         Job job=new Job(conf); 
  32.         job.setJobName("readTextVector with Input:"+arg0[1]); 
  33.         job.setJarByClass(ReadTextVectorWritable.class); 
  34.         job.setInputFormatClass(SequenceFileInputFormat.class);       
  35.         job.setMapperClass(RM.class); 
  36.         job.setMapOutputKeyClass(Text.class); 
  37.         job.setMapOutputValueClass(Text.class); 
  38.         job.setNumReduceTasks(0); 
  39.         SequenceFileInputFormat.addInputPath(job, new Path(arg0[1])); 
  40.         FileOutputFormat.setOutputPath(job, new Path(arg0[3]));       
  41.         return job.waitForCompletion(true)? 0:-1
  42.     }     
  43.     public static class RM extends Mapper<Text,VectorWritable,Text,Text>{ 
  44.         public void map(Text key,VectorWritable value,Context context)throws InterruptedException,IOException{ 
  45.             Vector vector=value.get(); 
  46.             context.write(key, new Text(vector.asFormatString())); 
  47.         } 
  48.     } 
  49.     public static void main(String[] args) throws Exception{ 
  50.         ToolRunner.run(new Configuration(), new ReadTextVectorWritable(), args); 
  51.     } 

然后查看hdfs上面的输入数据,如下:

 


对于上面的数据,其实应该和下面的数据效果是一样的:

 

[html] view plaincopy
 
  1. 1    {1:3.45,2:4.67,3:2.34} 
  2. 2    {1:4.65,3:4.62,3:4.34} 
  3. 3    {1:5.95,5:4.67,3:2.24} 

第一个代表一个样本号,冒号前面代表维度,冒号后面代表相应维度的大小。猜测:对于reuters数据,应该是把所有的单词全部排序,然后按照一定的规则进行编码(可以是从零到n的编码,所以冒号前面的数字就代表某一个单词),后面的数值应该是该单词在文件中的重要性(?这个应该是有一个pagerank的算法之类的);

 

有了上面的想法后就可以直接构造一定的输入数据(自己构造少量数据就可以对算法有很清晰的认识),然后把canopy算法的代码改为java代码(不使用hadoop就可以跑的代码),然后就可以进行调试分析其算法逻辑了。





收藏 推荐 打印 | 录入: | 阅读:
相关新闻      
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款