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. 基于Json.NET自己实现MVC中的JsonValueProviderFactory

    写了博文ASP.NET MVC 3升级至MVC 5.1的遭遇:“已添加了具有相同键的项”之后,继续看着System.Web.Mvc.JsonValueProviderFactory的开源代码. 越看越 ...

  2. 【51nod】1934 受限制的排列

    题解 这题还要判无解真是难受-- 我们发现我们肯定能确定1的位置,1左右的两个区间是同理的可以确定出最小值的位置 我们把区间最小值看成给一个区间+1,构建出笛卡尔树,就求出了每一次取最小值和最小值左右 ...

  3. JSP的学习二(指令与标签)

    一:page指令 1.JSP的指令 放在<%@ 指令 属性=“值”%> 主要有page,include,tablib. 2.page指令 用于定义JSP页面的各种属性,作用于是JSP的整个 ...

  4. console在ie下不兼容的问题(console在ie9下阻碍页面的加载,打开页面一片空白)

    在页面中加入以下代码: window.console = window.console || (function() { var c = {}; c.log = c.warn = c.debug = ...

  5. Django网站搭建(相关命令-Win10环境)

    为什么需要使用virtualenv? 虚拟环境的作用是创建一个独立的python环境,将每一个应用的环境独立开来,解决了不同应用及多版本之间的冲突问题.在开发的日常中,我们会将python及配套的应用 ...

  6. CentOS 7下MySQL5.7.23的服务配置参数测试

    CentOS 7默认安装MySQL5.7.23,服务管理发生了变化,从sysvinit(service mysql start)变化为systemd(systemctl start mysqld.se ...

  7. 洛谷——P1231 教辅的组成

    P1231 教辅的组成 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习 ...

  8. Android中利用ant进行多渠道循环批量打包

    公司负责Android开发的小伙伴学习能力稍微偏弱,交代给他的自动化打包的任务,弄了好久依然没有成效.无奈只好亲自出手. 没有想到过程很顺利,我完全按照如下文章的步骤进行: 主要参考: Android ...

  9. Codeforces Beta Round #97 (Div. 1) C. Zero-One 数学

    C. Zero-One 题目连接: http://codeforces.com/contest/135/problem/C Description Little Petya very much lik ...

  10. mybatis_mybatis写mapper文件注意事项

    xml中某些特殊符号作为内容信息时需要做转义,否则会对文件的合法性和使用造成影响 < < > > & & &apos; ' " " ...