[英]Groupby and list comprehension headache in python
我从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),但是这个groupby
和sum(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.
通过...分组
这是itertools
模块中的groupby
函数,在此处记录 。 data
“按”将itemgetter(0)
(来自operator
模块的itemgetter
类的实例,在此记录 )的结果“分组”到每个元素。 它返回成对的(关键结果,iterator-over-elements-with-key)。 因此,每次循环时, current_word
是一堆data
行共有的“字”(index-0,即第一项,由itemgetter
提取), group
是data
行上的迭代器用那个word
。 如代码文档中所述,文件的每一行都有两个单词:实际的“单词”和计数(用于解释为数字的文本)
sum(current_word的int(count),group中的count)
这意味着正是它说 :对的整数值的总和count
,每个( current_word
, count
中找到)对group
。 如上所述,每个group
是来自data
一组线。 因此,我们采用以current_word
开头的所有行,将其字符串count
数值转换为整数,然后将它们相加。
我如何修改这个块,以便它基本上继续做它现在做的事情,但是有第二个计数器值? 即输入是(word,count1,count2),输出是(word,count1,count2)。
那么,您希望每个计数代表什么,以及您希望数据来自何处?
我将采用我认为最简单的解释:您将修改数据文件以在每一行上有三个项目,并且您将分别从每列数字中获取总和。
groupby
将是相同的,因为我们仍然以相同的方式对行进行分组,并且我们仍然根据“单词”对它们进行分组。
sum
部分需要计算两个值:第一列数字的总和和第二列数字的总和。
当我们遍历group
,我们将获得三个值的集合,因此我们想要将它们解压缩为三个值:例如current_word, group_a, group_b
。 对于其中的每一个,我们希望将整数转换应用于每行上的两个数字。 这给了我们一系列数字序列; 如果我们想要添加所有第一个数字和所有第二个数字,那么我们应该制作一对数字序列。 为此,我们可以使用另一个名为izip
itertools
函数。 然后我们可以将它们分别相加,将它们再次打包成两个独立的数字序列变量,并对它们求和。
从而:
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
)
)
虽然在打印语句中使用该结果会有些棘手:)
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))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.