In this post we'll see how to compute the mean of the max temperatures of every month for the city of Milan. 
The temperature data is taken from http://archivio-meteo.distile.it/tabelle-dati-archivio-meteo/, but since the data are shown in tabular form, we had to sniff the HTTP conversation to see that the data come from this URL and are in JSON format. 
Using Jackson, we could transform this JSON into a format simpler to use with Hadoop: CSV. The result of conversion is this:

01012000,-4.0,5.0
02012000,-5.0,5.1
03012000,-5.0,7.7
04012000,-3.0,9.7
...

If you're curious to see how we transformed it, take a look at the source code.

Let's look at the mapper class for this job:

public static class MeanMapper extends Mapper<Object, Text, Text, SumCount> {

    private final int DATE = 0;
private final int MIN = 1;
private final int MAX = 2; private Map<Text, List<Double>> maxMap = new HashMap<>(); @Override
public void map(Object key, Text value, Context context) throws IOException, InterruptedException { // gets the fields of the CSV line
String[] values = value.toString().split((",")); // defensive check
if (values.length != 3) {
return;
} // gets date and max temperature
String date = values[DATE];
Text month = new Text(date.substring(2));
Double max = Double.parseDouble(values[MAX]); // if not present, put this month into the map
if (!maxMap.containsKey(month)) {
maxMap.put(month, new ArrayList<Double>());
} // adds the max temperature for this day to the list of temperatures
maxMap.get(month).add(max);
} @Override
protected void cleanup(Context context) throws IOException, InterruptedException { // loops over the months collected in the map() method
for (Text month: maxMap.keySet()) { List<Double> temperatures = maxMap.get(month); // computes the sum of the max temperatures for this month
Double sum = 0d;
for (Double max: temperatures) {
sum += max;
} // emits the month as the key and a SumCount as the value
context.write(month, new SumCount(sum, temperatures.size()));
}
}
}

How we've seen in the last posts (about optimization and combiners), in the mapper we first put values into a map, and when the input is over, we loop over the keys to sum the values and to emit them. Note that we use the SumCount class, which is a utility class that wraps the two values we need to compute a mean: the sum of all the values and the number of values. 
A common error in this kind of computation is making the mapper directly emit the mean; let's see what it can happen if we suppose to have a dataset like this:

01012000,0,10.0
02012000,0,20.0
03012000,0,2.0
04012000,0,4.0
05012000,0,3.0

and two mappers, which will receive the first two and the last three lines respectively. The first mapper will compute a mean of 15.0, given from (10.0 + 20.0) / 2. The second will compute a mean of 3.0, given from (2.0 + 4.0 + 3.0) / 3. When the reducer receive this two values, it sums them together and divide by two, so that the mean will be: 9.0, given from (15.0 + 3.0) / 2. But the correct mean for the values in this example is 7.8, which is given from (10.0 + 20.0 + 4.0 + 2.0 + 3.0) / 5. 
This error is due to the fact that any mapper can receive any number of lines, so the value it will emit is only a part of the information needed to compute a mean.

If instead of emitting the mean we emit the sum of the values and the number of values, we can overcome the problem. In the example we saw before, the first mapper will emit the pair (30.0, 2) and the second (9.0, 3); if we sum the values and divide it by the sum of the numbers, we obtain the right result.

Let's get back to our job and look at the reducer:

public static class MeanReducer extends Reducer<text, sumcount,="" text,="" doublewritable=""> {

    private Map<text, sumcount=""> sumCountMap = new HashMap<>();

    @Override
public void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException { SumCount totalSumCount = new SumCount(); // loops over all the SumCount objects received for this month (the "key" param)
for (SumCount sumCount : values) { // sums all of them
totalSumCount.addSumCount(sumCount);
} // puts the resulting SumCount into a map
sumCountMap.put(new Text(key), totalSumCount);
} @Override
protected void cleanup(Context context) throws IOException, InterruptedException { // loops over the months collected in the reduce() method
for (Text month: sumCountMap.keySet()) { double sum = sumCountMap.get(month).getSum().get();
int count = sumCountMap.get(month).getCount().get(); // emits the month and the mean of the max temperatures for the month
context.write(month, new DoubleWritable(sum/count));
}
}
}

The reducer is simpler because it has just to retrieve all the SumCount objects emitted from the reducers and add them together. After receiving the input, it loops over the map of the SumCount objects and emits the month and the mean.

from: http://andreaiacono.blogspot.com/2014/04/computing-mean-with-mapreduce.html

计算均值mean的MapReduce程序Computing mean with MapReduce的更多相关文章

  1. 用Python语言写Hadoop MapReduce程序Writing an Hadoop MapReduce Program in Python

    In this tutorial I will describe how to write a simple MapReduce program for Hadoop in the Python pr ...

  2. 一起学Hadoop——使用IDEA编写第一个MapReduce程序(Java和Python)

    上一篇我们学习了MapReduce的原理,今天我们使用代码来加深对MapReduce原理的理解. wordcount是Hadoop入门的经典例子,我们也不能免俗,也使用这个例子作为学习Hadoop的第 ...

  3. HDFS设计思路,HDFS使用,查看集群状态,HDFS,HDFS上传文件,HDFS下载文件,yarn web管理界面信息查看,运行一个mapreduce程序,mapreduce的demo

    26 集群使用初步 HDFS的设计思路 l 设计思想 分而治之:将大文件.大批量文件,分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析: l 在大数据系统中作用: 为各类分布式 ...

  4. [python]使用python实现Hadoop MapReduce程序:计算一组数据的均值和方差

    这是参照<机器学习实战>中第15章“大数据与MapReduce”的内容,因为作者写作时hadoop版本和现在的版本相差很大,所以在Hadoop上运行python写的MapReduce程序时 ...

  5. 怎样通过Java程序提交yarn的mapreduce计算任务

    因为项目需求,须要通过Java程序提交Yarn的MapReduce的计算任务.与一般的通过Jar包提交MapReduce任务不同,通过程序提交MapReduce任务须要有点小变动.详见下面代码. 下面 ...

  6. 简单的java Hadoop MapReduce程序(计算平均成绩)从打包到提交及运行

    [TOC] 简单的java Hadoop MapReduce程序(计算平均成绩)从打包到提交及运行 程序源码 import java.io.IOException; import java.util. ...

  7. mapreduce程序编写(WordCount)

    折腾了半天.终于编写成功了第一个自己的mapreduce程序,并通过打jar包的方式运行起来了. 运行环境: windows 64bit eclipse 64bit jdk6.0 64bit 一.工程 ...

  8. 基于Hbase数据的Mapreduce程序环境开发

    一.实验目标 编写Mapreduce程序,以Hbase表数据为Map输入源,计算结果输出到HDFS或者Hbase表中. 在非CDH5的Hadoop集群环境中,将编写好的Mapreduce程序整个工程打 ...

  9. 从零开始学习Hadoop--第2章 第一个MapReduce程序

    1.Hadoop从头说 1.1 Google是一家做搜索的公司 做搜索是技术难度很高的活.首先要存储很多的数据,要把全球的大部分网页都抓下来,可想而知存储量有多大.然后,要能快速检索网页,用户输入几个 ...

随机推荐

  1. LoadRunner如何获得参数化中每个关键字的搜索响应时间

    LoadRunner如何获得参数化中每个关键字的搜索响应时间 在测试搜索引擎时我们一般采用大量的搜索关键字,有时有必要了解在并发访问的情况下每个关键字的响应时间,一般如果不对脚本进行处理的话你可以获得 ...

  2. LoadRunner 11简单使用

    LoadRunner 11简单使用 开始菜单-->HP LoadRunner-->applications--->virtual user Generator 1>新建--&g ...

  3. Standard NSD file

    %pool: pool=system blockSize=256K layoutMap=cluster allowWriteAffinity=no %pool: pool=datapool block ...

  4. Acer宏碁暗影骑士3进阶版无法进入系统引导修复

    1.刚开机时,按住alt不放,不停点击F10进入恢复系统: 2.点击疑难解答,选择cmd: 3.以下是cmd命令,//注释不要复制 c: //进入C盘 cd windows cd system32 b ...

  5. Qt Quick快速入门之信号、槽

    信号和槽主要用于组件之间的通信,类似于.net和java中的委托. 使用QObject::connect方法将信号与槽关联起来,然后信号的发起者发出信号,接受者中的槽函数就会执行. 比如connect ...

  6. BZOJ 1061: [Noi2008]志愿者招募 [单纯形法]【学习笔记看另一篇吧】

    1061: [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3975  Solved: 2421[Submit][Stat ...

  7. [Luogu4724][模板]三维凸包(增量构造法)

    1.向量点积同二维,x1y1+x2y2+x3y3.向量叉积是行列式形式,(y1z2-z1y2,z1x2-x1z2,x1y2-y1x2). 2.增量构造法: 1)首先定义,一个平面由三个点唯一确定.一个 ...

  8. 【POJ】1835:宇航员【模拟】【三维行走】

    宇航员 Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 7228   Accepted: 3050 Description 问 ...

  9. wx小程序碎碎念

    对button组件的例子中,js代码的一点理解 for (var i = 0; i < types.length; ++i) { (function(type) { // 循环构建目标函数 pa ...

  10. Linux性能监控分析命令(五)—free命令介绍

    性能监控分析的命令包括如下:1.vmstat2.sar3.iostat4.top5.free6.uptime7.netstat8.ps9.strace10.lsof 命令介绍:free命令是监控Lin ...