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. Asp.Net MVC路由调试工具-RouteDebugger

    1.获取方式 第一种方法: 在程序包控制台中执行命令 PM> Install-Package routedebugger 安装成功后Web.config文件中会自动加入行 <add key ...

  2. Hive分区和桶的概念

    Hive 已是目前业界最为通用.廉价的构建大数据时代数据仓库的解决方案了,虽然也有 Impala 等后起之秀,但目前从功能.稳定性等方面来说,Hive 的地位尚不可撼动. 其实这篇博文主要是想聊聊 S ...

  3. C# 中使用 Task 实现提前加载

    介绍一种/两种可以提前做点什么事情的方法. 场景 在UI线程中执行耗时操作,如读取大文件,为了不造成UI卡顿,常采用异步加载的方式,即 async/await . 通常的写法是这样的: private ...

  4. mysql 错误解决:Plugin 'FEDERATED' is disabled. /usr/sbin/mysqld: Table 'mysql.plugin' doesn't exist

    今天安装完Mysql后,开启发生了错误: 1.打开相应文件夹,查看错误信息: 2.打开错误信息文件,查看错误原因是:Plugin 'FEDERATED' is disabled. /usr/sbin/ ...

  5. iOS 11开发教程(七)编写第一个iOS11代码Hello,World

    iOS 11开发教程(七)编写第一个iOS11代码Hello,World 代码就是用来实现某一特定的功能,而用计算机语言编写的命令序列的集合.现在就来通过代码在文本框中实现显示“Hello,World ...

  6. dataTransfer 对象

    dataTransfer 对象 提供了对于预定义的剪贴板格式的访问,以便在拖曳操作中使用. DHTML元素属性列表 属性 描述 dropEffect 设置或获取拖曳操作的类型和要显示的光标类型. ef ...

  7. Codeforces.739E.Gosha is hunting(DP 带权二分)

    题目链接 \(Description\) 有\(n\)只精灵,两种精灵球(高级和低级),每种球能捕捉到第\(i\)只精灵的概率已知.求用\(A\)个低级球和\(B\)个高级球能捕捉到精灵数的最大期望. ...

  8. SPOJ GSS

    GSS1 题目大意:给出一个数列,多次询问区间最长连续子段和 题解:线段树维护区间最长连续子段和gss,区间从最左元素开始的最长连续子段和lgss 区间以最右元素为结尾的最长连续子段和rgss以及区间 ...

  9. 【二分】【预处理】zoj4029 Now Loading!!!

    题意:给定一个序列,多次询问 将a数组从小到大排序,下面那个值只有不超过32种,于是预处理f[i][j],表示分母为i时,aj/i的前缀和是多少. 然后对于一个给定的p,一定将分母划分成了一些连续的段 ...

  10. Codeforces Round #196 (Div. 2) A. Puzzles 水题

    A. Puzzles Time Limit: 2 Sec  Memory Limit: 60 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem ...