[英]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.