在python中的Groupby和列表理解头痛

时间:2011-11-23 01:09:53

标签: python functional-programming list-comprehension

我从Hadoop教程中得到了这个。它是一个reducer,基本上从stdin接收(word,count)对并对它们求和。

def read_mapper_output(file, separator='\t'):
    for line in file:
        yield line.rstrip().split(separator, 1)

def main(separator='\t'):
    data = read_mapper_output(sys.stdin, separator=separator)
    for current_word, group in groupby(data, itemgetter(0)):
        try:
            total_uppercount = sum(int(count) for current_word, count in group)
            print "%s%s%d" % (current_word, separator, total_count)
        except ValueError:
            pass

现在,我希望能够接受元组(word,count1,count2),但这个groupbysum(int(count for current_word, count in group)业务对我来说完全难以理解。我如何修改这个块,以便它基本上继续做它现在做的事情,但是有第二个计数器值? 即输入是(word,count1,count2),输出是(word,count1,count2)。

编辑1:

from itertools import groupby, izip
from operator import itemgetter
import sys

def read_mapper_output(file, separator='\t'):
    for line in file:
        yield line.rstrip().split(separator, 2)

def main(separator='\t'):
    data = read_mapper_output(sys.stdin, separator=separator)
    for current_word, group in groupby(data, itemgetter(0)):
        try:
            counts_a, counts_b = izip((int(count_a), int(count_b)) for current_word, count_a, count_b in group)
            t1, t2 = sum(counts_a), sum(counts_b)
            print "%s%s%d%s%d" % (current_word, separator, t1, separator, t2)
        except ValueError:
            pass

这是一个Hadoop作业,所以输出如下:

11/11/23 18:44:21 INFO streaming.StreamJob:  map 100%  reduce 0%
11/11/23 18:44:30 INFO streaming.StreamJob:  map 100%  reduce 17%
11/11/23 18:44:33 INFO streaming.StreamJob:  map 100%  reduce 2%
11/11/23 18:44:42 INFO streaming.StreamJob:  map 100%  reduce 12%
11/11/23 18:44:45 INFO streaming.StreamJob:  map 100%  reduce 0%
11/11/23 18:44:51 INFO streaming.StreamJob:  map 100%  reduce 3%
11/11/23 18:44:54 INFO streaming.StreamJob:  map 100%  reduce 7%
11/11/23 18:44:57 INFO streaming.StreamJob:  map 100%  reduce 0%
11/11/23 18:45:05 INFO streaming.StreamJob:  map 100%  reduce 2%
11/11/23 18:45:06 INFO streaming.StreamJob:  map 100%  reduce 8%
11/11/23 18:45:08 INFO streaming.StreamJob:  map 100%  reduce 7%
11/11/23 18:45:09 INFO streaming.StreamJob:  map 100%  reduce 3%
11/11/23 18:45:12 INFO streaming.StreamJob:  map 100%  reduce 100%
...
11/11/23 18:45:12 ERROR streaming.StreamJob: Job not Successful!

来自日志:

java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 1
    at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:311)
    at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:545)
    at org.apache.hadoop.streaming.PipeReducer.close(PipeReducer.java:137)
    at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:473)
    at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:411)
    at org.apache.hadoop.mapred.Child.main(Child.java:170)

java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 1
    at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:311)
    at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:545)
    at org.apache.hadoop.streaming.PipeReducer.close(PipeReducer.java:137)
    at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:473)
    at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:411)
    at org.apache.hadoop.mapred.Child.main(Child.java:170)

Shuffle Error: Exceeded MAX_FAILED_UNIQUE_FETCHES; bailing-out.

2 个答案:

答案 0 :(得分:2)

  

GROUPBY

这是groupby模块中的itertools函数,记录为heredata“按”将itemgetter(0)itemgetter类的operator类的实例,记录为here)应用于每个元素的结果“按”分组“ 。它返回成对的(关键结果,iterator-over-elements-with-key)。因此,每次循环时,current_word都是一串data行共有的“单词”(索引为0,即第一项,由itemgetter提取) ,group是以data开头的word行的迭代器。如代码文档中所述,文件的每一行都有两个单词:实际的“单词”和计数(用于解释为数字的文本)

  

sum(current_word的int(count),group中的count)

意味着它所说的count的整数值之和,对于每个current_wordcount)对中的group group。如上所述,每个data是来自current_word的一组行。因此,我们采用以count开头的所有行,将其字符串groupby值转换为整数,然后将它们相加。

  

如何修改此块,以便它基本上继续执行它现在所做的操作,但是具有第二个计数器值?即输入是(word,count1,count2),输出是(word,count1,count2)。

那么,您希望每个计数代表什么,以及您希望数据来自何处?

我将采取我认为最简单的解释:您将修改数据文件以在每一行上有三个项目,并且您将获得总和分别来自每列数字。

sum将是相同的,因为我们仍然以相同的方式对我们获得的行进行分组,并且我们仍然根据“单词”对它们进行分组。

group部分需要计算两个值:第一列数字的总和和第二列数字的总和。

当我们迭代current_word, group_a, group_b时,我们将获得三个值的集合,因此我们要将它们解压缩为三个值:例如itertools。对于其中的每一个,我们希望将整数转换应用于每行上的两个数字。这给了我们一系列数字序列;如果我们想要添加所有第一个数字和所有第二个数字,那么我们应该制作一对数字序列。为此,我们可以使用另一个名为izip的{​​{1}}函数。然后我们可以将它们分别相加,通过将它们再次打包成两个独立的数字序列变量,并对它们求和。

因此:

counts_a, counts_b = izip(
    (int(count_a), int(count_b)) for current_word, count_a, count_b in group
)
total_a, total_b = sum(counts_a), sum(counts_b)

或者我们可以通过再次执行相同的操作(x中的y代表y)来制作一对计数:

totals = (
    sum(counts)
    for counts in izip(
        (int(count_a), int(count_b)) for current_word, count_a, count_b in group
    )
)

虽然在print语句中使用该结果会有点棘手:)

答案 1 :(得分:0)

from collections import defaultdict

def main(separator='\t'):
    data = read_mapper_output(sys.stdin, separator=separator)
    counts = defaultdict(lambda: [0, 0])
    for word, (count1, count2) in data:
        values = counts[word]
        values[0] += count1
        values[1] += count2

    for word, (count1, count2) in counts.iteritems():
        print('{0}\t{1}\t{2}'.format(word, count1, count2))