MapReduce编程基础(二)——数值概要(计算中位数、标准差)[内存优化]
来源:互联网 发布:淘宝上买东西不花钱 编辑:程序博客网 时间:2024/06/06 05:06
1.中位数与标准差计算示例【内存优化】
在前一篇博客中,我介绍了一种计算中位数和标准差的方法,但是该方法需要将所有的数据读入内存再进行遍历,不够优化。所以在这里,我们将前一种方法进行优化,
将所有的数值都插入列表会产生大量的重复的元素。一个规避重复元素的方法就是保存元素的计数。
例如:要保存<1,1,1,1,2,2,3,4,5,5,5>可以使用排序好的值到计数的映射来代替:(1->4,2->2,3->1,4->1,5->3).
核心概念还是与前一种方法相同,但是这样可以减少存放到内存的数据量。而且这个方法还有一个优点就是可以使用combiner来聚合map端的计数。
2.数据集
本示例使用Movielens数据集中的u1.base文件,MovieLens数据集是一个用户对电影的评分数据集,在后续的示例中我们将一直使用这个数据集,我会将这个数据集上传到CSDN方便大家下载,文件的格式如下所示:
第1列到第4列分别代表用户ID**,项目ID**,用户对项目的评分,时间戳
1 1 5 8749657581 2 3 8768931711 3 4 8785429601 4 3 8768931191 5 3 8897517121 7 4 8750715611 8 1 875072484... .... ....943 1067 2 875501756943 1074 4 888640250943 1188 3 888640250943 1228 3 888640275943 1330 3 888692465
3.问题
对于给定的用户项目评分数据,确定每个用户评分的中位数、均方差。
4.计算方案(内存优化版)
1)自定义Writab类存储输出数据
public class MedianStdDevImproveTuple implements Writable{ private float stdDev=0; private float median=0; private int rate=0; public void setStdDev(float stdDev){ this.stdDev=stdDev; } public double getStdDev(){ return stdDev; } public void setMedian(float median){ this.median=median; } public double getMedian(){ return median; } public void setRate(int rate){ this.rate=rate; } public double getRate(){ return rate; } @Override public void readFields(DataInput in) throws IOException { stdDev=in.readFloat(); median=in.readFloat(); rate=in.readInt(); } @Override public void write(DataOutput out) throws IOException { out.writeFloat(this.stdDev); out.writeFloat(this.median); out.writeInt(this.rate); } public String toString(){ return "medianValue:"+median+" "+"stdDev:"+stdDev; }}
2)mapper代码
public static class MedianStdDevImproveMapper extends Mapper<Object, Text, IntWritable, SortedMapWritable>{ private IntWritable outUserId=new IntWritable();//输出健 private IntWritable outRate=new IntWritable();//输出值 private final LongWritable ONE=new LongWritable(1); public void map(Object key, Text value ,Context context) throws IOException, InterruptedException{ String[] data=value.toString().split(" "); if(data.length==4){ //输出的键 outUserId.set(Integer.valueOf(data[0])); //输出的值,用户的评分 outRate.set(Integer.valueOf(data[2])); //定义一个Writable类来存放键和值的映射 SortedMapWritable outCommentLength=new SortedMapWritable(); outCommentLength.put(outRate, ONE); context.write(outUserId, outCommentLength); } } }
2)reducer代码
public static class MedianStdDevImproveReducer extends Reducer<IntWritable, SortedMapWritable, IntWritable, MedianStdDevTuple>{ private MedianStdDevTuple result=new MedianStdDevTuple(); private TreeMap<Integer,Long> RateCounts=new TreeMap<Integer,Long>(); public void reduce(IntWritable key, Iterable<SortedMapWritable> values,Context context) throws IOException, InterruptedException{ float sum=0; long totalcount=0; RateCounts.clear(); result.setStdDev(0.0); result.setMedian(0.0); for(SortedMapWritable v:values){ for(Entry<WritableComparable,Writable> entry:v.entrySet()){ int rate=((IntWritable)entry.getKey()).get(); long count=((LongWritable)entry.getValue()).get(); totalcount+=count; sum+=rate*count; Long storedCount=RateCounts.get(rate); if(storedCount==null){ //如果storedCount==null说明是第一条数据 RateCounts.put(rate, count); }else{ //后续依次存入递增的值 RateCounts.put(rate, storedCount+count); } } } //中位数的位置 long x=2; long medianIndex= totalcount/x; long previousCount=0; long lastCount=0; int preKey=0; for(Entry<Integer,Long> entry:RateCounts.entrySet()){ lastCount=previousCount+entry.getValue(); //*首先分为两种情况: //* 1.总的评分数目是奇数:说明中位数就存在于当前key值对应的范围内,当前key值就是中位数 // * 2.总的评分数目是偶数:1)前后两个数在同一个范围类,则当前key值就是中位数 // * 2)前后两个数不在同一个范围内,只满足其中一个数位于边界,即previousCount==medianIndex,则取前一个key和后一个key的和相除得到中位数 // * if(previousCount<=medianIndex&&medianIndex<lastCount){ if(totalcount%2==0&&previousCount==medianIndex){ result.setMedian((float)(entry.getKey()+preKey)/2.0f); }else{ result.setMedian((float)entry.getKey()); } break;//中位数已经找到,跳出循环 } previousCount=lastCount;//更新 preKey=entry.getKey();//更新 } //计算均方差 float mean=sum/totalcount; float sumOfSquares=0.0f; for(Entry<Integer, Long> entry:RateCounts.entrySet()){ sumOfSquares+=(entry.getKey()-mean)*(entry.getKey()-mean)*entry.getValue(); } result.setStdDev((float)(Math.sqrt(sumOfSquares/(totalcount-1)))); context.write(key, result); } }
2)Combiner优化代码
public static class MedianStdDevImproveCombiner extends Reducer<IntWritable, SortedMapWritable,IntWritable, SortedMapWritable>{ public void reduce(IntWritable key, Iterable<SortedMapWritable> values,Context context) throws IOException, InterruptedException{ SortedMapWritable outValue=new SortedMapWritable(); for(SortedMapWritable v:values){ for(Entry<WritableComparable, Writable> entry:v.entrySet()){ LongWritable count=(LongWritable)outValue.get(entry.getKey());//获取当前的计数 if(count==null){ outValue.put(entry.getKey(), new LongWritable(((LongWritable)entry.getValue()).get())); }else{ outValue.put(entry.getKey(),new LongWritable(count.get()+((LongWritable)entry.getValue()).get())); } } } context.write(key, outValue); } }
4.总结
在对有大量重复数据的数据进行存储时,可以采用本例展示的存储数据出现次数的方式来节省存储空间。
本例特别注意:在对输出文件进行设置的时候需要注意,combiner的输入和输出类型需要与map的输出类型相同,不然会出现没有输出的情况。
详情可以参考博客:http://blog.csdn.net/lucktroy/article/details/7957120
感谢该博主分享经验,帮我找出了程序中存在的问题!
阅读全文
0 0
- MapReduce编程基础(二)——数值概要(计算中位数、标准差)[内存优化]
- MapReduce编程基础(二)——数值概要(计算中位数、标准差)
- MapReduce编程基础(二)——数值概要(计算最大值、最小值、平均值)
- mapreduce编程实例(4)-求中位数和标准差
- mapreduce编程实例(4)-求中位数和标准差
- MapReduce编程实战(二)——20151112
- 数值优化(Numerical Optimization)学习系列(二)-无约束优化的基础
- MapReduce编程基础(一)——基础知识
- MapReduce编程实例(二)
- matlab基础学习——数值计算
- 云计算基础(三):HDFS+MapReduce
- 概率统计基础(2)方差、标准差
- 【并行计算】用MPI进行分布式内存编程(二)
- 数值计算与优化(共轭梯度法和QR)
- MapReduce编程基础—学习笔记[2]
- Java基础—网络编程(二)
- 数值计算——线性最小二乘问题
- 深度学习之数值计算(二)poor conditioning
- Swift3.1 最新开启用户授权方法
- Php性能分析-xhprof
- python 生成器generator
- ubuntu14.04安装vnc服务器并创建多人用户
- struct与union的对齐方式解析
- MapReduce编程基础(二)——数值概要(计算中位数、标准差)[内存优化]
- java instanceof 运算符 判断类的实例
- 【设计模式】——责任链模式
- Spark学习札记
- d3 绘制中国地图
- HDU
- 对面向对象的一些思考
- LA 3029 City Game (DP||单调栈)
- 美素数 HDU