python中的map和reduce

MapReduce

什么是MapReduce

摘自wiki中關(guān)于MapReduce的說明

MapReduceGoogle提出的一個軟件架構(gòu)栈源,用于大規(guī)模數(shù)據(jù)集(大于1TB)的并行運算孵滞。概念“Map(映射)”和“Reduce(歸納)”,及他們的主要思想履肃,都是從函數(shù)式編程語言借來的查描,還有從矢量編程語言借來的特性。[1]

當(dāng)前的軟件實現(xiàn)是指定一個Map(映射)函數(shù)昆著,用來把一組鍵值對映射成一組新的鍵值對,指定并發(fā)的Reduce(歸納)函數(shù)术陶,用來保證所有映射的鍵值對中的每一個共享相同的鍵組宣吱。

簡單來說,一個映射函數(shù)就是對一些獨立元素組成的概念上的列表(例如瞳别,一個測試成績的列表)的每一個元素進(jìn)行指定的操作(比如,有人發(fā)現(xiàn)所有學(xué)生的成績都被高估了一分杭攻,他可以定義一個“減一”的映射函數(shù)祟敛,用來修正這個錯誤。)兆解。事實上馆铁,每個元素都是被獨立操作的,而原始列表沒有被更改锅睛,因為這里創(chuàng)建了一個新的列表來保存新的答案埠巨。這就是說,Map操作是可以高度并行的现拒,這對高性能要求的應(yīng)用以及并行計算領(lǐng)域的需求非常有用辣垒。
而歸納操作指的是對一個列表的元素進(jìn)行適當(dāng)?shù)暮喜ⅲɡ^續(xù)看前面的例子,如果有人想知道班級的平均分該怎么做印蔬?他可以定義一個歸納函數(shù)勋桶,通過讓列表中的奇數(shù)(odd)或偶數(shù)(even)元素跟自己的相鄰的元素相加的方式把列表減半,如此遞歸運算直到列表只剩下一個元素侥猬,然后用這個元素除以人數(shù)例驹,就得到了平均分)。雖然他不如映射函數(shù)那么并行退唠,但是因為歸納總是有一個簡單的答案鹃锈,大規(guī)模的運算相對獨立,所以歸納函數(shù)在高度并行環(huán)境下也很有用瞧预。

python中的map和reduce

python中內(nèi)置支持map和reduce操作

map和reduce的原型

map函數(shù)原型為

map(*function*, *iterable*, *...*) -> list

意思是map函數(shù)對第二個參數(shù)(或者后面更多的參數(shù))進(jìn)行迭代屎债,將迭代的元素作為參數(shù)傳遞給function仅政,function將處理過的結(jié)果保存在一個list里面并返回這個list

reduce函數(shù)原型為

reduce(*function*, *iterable*[, *initializer*]) -> value

實現(xiàn)差不多等同于下面的代碼

def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
        try:
            initializer = next(it)
        except StopIteration:
            raise TypeError('reduce() of empty sequence with no initial value')
    accum_value = initializer
    for x in it:
        accum_value = function(accum_value, x)
    return accum_value

舉例,假設(shè)現(xiàn)在有幾個list扔茅,想要統(tǒng)計它們總的元素個數(shù)已旧,利用map-reduce的思想可以這樣實現(xiàn)

a = [1, 2, 3]
b = [4, 5, 6, 7]
c = [8, 9, 1, 2, 3]
L = map(lambda x: len(x), [a, b, c])
N = reduce(lambda x, y: x + y, L)

可以看到,上面的代碼

  1. 沒有寫出一個循環(huán)
  2. 沒有臨時變量的狀態(tài)被改變

卻簡潔有力地描述了問題的解決辦法召娜,因此可讀性是很高的运褪。這也是函數(shù)式編程的特性。

但是上面的寫法和下面的方法解決問題的效率幾乎是一樣的玖瘸。

result = sum([len(item) for item in [a, b, c]])

在面對非常大的數(shù)據(jù)量的時候秸讹,這樣的處理方式效率并不理想。

并行的解法

提到并行雅倒,首先想到的是多線程璃诀。但是,python中有GIL蔑匣,并不能很好地利用多處理器的進(jìn)行并發(fā)的計算劣欢。
所以想到python中的multiprocessing模塊,這個模塊提供了Pool這個類來管理任務(wù)的進(jìn)程池裁良,并且這個類提供了并行的map方法凿将。這個map方法和之前提到的概念是很類似的,但是并不是說它處理的是MapReduce中的map步驟价脾。
以經(jīng)典的wordcount問題為例牧抵,直接上代碼。

def my_map(l):
    results = []
    for w in l:
        # True if w contains non-alphanumeric characters
        if not w.isalnum():
            w = sanitize(w)
        # True if w is a title-cased token
        results.append((w.lower(), 1))
    return results

def my_partition(l):
    tf = {}
    for sublist in l:
        for p in sublist:
            # Append the tuple to the list in the map
            tf[p[0]] = tf.get(p[0], []) + [p]
    return tf

def my_reduce(mapping):
    return (mapping[0], sum(pair[1] for pair in mapping[1]))

整個計算流程被拆成了Map, Partition, Reduce三個步驟

  1. my_map方法
    傳入一個token的list侨把,去掉token首尾的標(biāo)點符號犀变,并且返回(token.lower(), 1)的一個list
  2. my_partition方法
    傳入上面my_map處理的結(jié)果,返回一個dict秋柄,key為token获枝,value為所有(token, 1)的一個list
  3. my_reduce方法
    統(tǒng)計各個單詞出現(xiàn)的次數(shù)
def sanitize(w):
    # 去除字符串首尾的標(biāo)點符號
    while len(w) > 0 and not w[0].isalnum():
        w = w[1:]    # String punctuation from the back
    while len(w) > 0 and not w[-1].isalnum():
        w = w[:-1]
    return w

def load(path):
    word_list = []
    f = open(path, "r")
    for line in f:
        word_list.append(line)
    return (''.join(word_list)).split()

def chunks(l, n):
    for i in xrange(0, len(l), n):
        yield l[i:i + n]

def tuple_sort(a, b):
    if a[1] < b[1]:
        return 1
    elif a[1] > b[1]:
        return -1
    else:
        return cmp(a[0], b[0])

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print "Program requires path to file for reading!"
        sys.exit(1)
    text = load(sys.argv[1])
    pool = Pool(processes=8, )
    partitioned_text = list(chunks(text, len(text) / 8))
    single_count_tuples = pool.map(my_map, partitioned_text)
    token_to_tuples = my_partition(single_count_tuples)
    term_frequencies = pool.map(my_reduce, token_to_tuples.items())
    term_frequencies.sort(tuple_sort)

這里利用了multiprocess的map方法,對map和reduce方法進(jìn)行了多進(jìn)程的處理华匾。共設(shè)立了8個進(jìn)程映琳,把讀取到的文件分成8塊進(jìn)行處理。

需要說明的是蜘拉,這里完全是為了仿照hadoop的流程進(jìn)行的計算萨西。效率可能并不是最優(yōu)的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旭旭,一起剝皮案震驚了整個濱河市谎脯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌持寄,老刑警劉巖源梭,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娱俺,死亡現(xiàn)場離奇詭異,居然都是意外死亡废麻,警方通過查閱死者的電腦和手機(jī)荠卷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烛愧,“玉大人油宜,你說我怎么就攤上這事×耍” “怎么了慎冤?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沧卢。 經(jīng)常有香客問我蚁堤,道長,這世上最難降的妖魔是什么但狭? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任披诗,我火速辦了婚禮,結(jié)果婚禮上立磁,老公的妹妹穿的比我還像新娘藤巢。我一直安慰自己,他們只是感情好息罗,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著才沧,像睡著了一般迈喉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上温圆,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天挨摸,我揣著相機(jī)與錄音,去河邊找鬼岁歉。 笑死得运,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锅移。 我是一名探鬼主播熔掺,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼非剃!你這毒婦竟也來了置逻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤备绽,失蹤者是張志新(化名)和其女友劉穎券坞,沒想到半個月后鬓催,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡恨锚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年宇驾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猴伶。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡课舍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜗顽,到底是詐尸還是另有隱情布卡,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布雇盖,位于F島的核電站忿等,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏崔挖。R本人自食惡果不足惜贸街,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望狸相。 院中可真熱鬧薛匪,春花似錦、人聲如沸脓鹃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘸右。三九已至娇跟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間太颤,已是汗流浹背苞俘。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留龄章,地道東北人吃谣。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像做裙,于是被迫代替她去往敵國和親岗憋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容