簡體   English   中英

多處理寫入pandas數據幀

[英]Multiprocessing writing to pandas dataframe

所以我試圖用以下代碼做的是讀取列表列表並將它們放入名為checker函數中,然后讓log_result處理函數checker的結果。 我試圖使用多線程執行此操作,因為變量名稱rows_to_parse實際上有數百萬行,因此使用多個核心應該會大大加快此過程的速度。

目前的代碼不起作用並導致Python崩潰。

我有的擔憂和問題:

  1. 想要在變量df中保存的現有df在整個過程中維護索引,否則log_result會對哪行需要更新感到困惑。
  2. 我很確定apply_async不是執行此任務的合適的多處理函數,因為我相信計算機讀取和寫入df的順序可能會破壞它?
  3. 我認為可能需要設置一個隊列來寫和讀df但我不確定我將如何去做。

謝謝你的幫助。

import pandas as pd
import multiprocessing
from functools import partial

def checker(a,b,c,d,e):
    match = df[(df['a'] == a) & (df['b'] == b) & (df['c'] == c) & (df['d'] == d) & (df['e'] == e)]
    index_of_match = match.index.tolist()
    if len(index_of_match) == 1: #one match in df
        return index_of_match
    elif len(index_of_match) > 1: #not likely because duplicates will be removed prior to: if "__name__" == __main__:
        return [index_of_match[0]]
    else: #no match, returns a result which then gets processed by the else statement in log_result. this means that [a,b,c,d,e] get written to the df
        return [a,b,c,d,e]



def log_result(result, dataf):
    if len(result) == 1: #
        dataf.loc[result[0]]['e'] += 1 
    else: #append new row to exisiting df
        new_row = pd.DataFrame([result],columns=cols)
        dataf = dataf.append(new_row,ignore_index=True)


def apply_async_with_callback(parsing_material, dfr):
    pool = multiprocessing.Pool()
    for var_a, var_b, var_c, var_d, var_e in parsing_material:
        pool.apply_async(checker, args = (var_a, var_b, var_c, var_d, var_e), callback = partial(log_result,dataf=dfr))
    pool.close()
    pool.join()



if __name__ == '__main__':
    #setting up main dataframe
    cols = ['a','b','c','d','e']
    existing_data = [["YES","A","16052011","13031999",3],
                    ["NO","Q","11022003","15081999",3],
                    ["YES","A","22082010","03012001",9]]

    #main dataframe
    df = pd.DataFrame(existing_data,columns=cols)

    #new data
    rows_to_parse = [['NO', 'A', '09061997', '06122003', 5],
                    ['YES', 'W', '17061992', '26032012', 6],
                    ['YES', 'G', '01122006', '07082014', 2],
                    ['YES', 'N', '06081992', '21052008', 9],
                    ['YES', 'Y', '18051995', '24011996', 6],
                    ['NO', 'Q', '11022003', '15081999', 3],
                    ['NO', 'O', '20112004', '28062008', 0],
                    ['YES', 'R', '10071994', '03091996', 8],
                    ['NO', 'C', '09091998', '22051992', 1],
                    ['YES', 'Q', '01051995', '02012000', 3],
                    ['YES', 'Q', '26022015', '26092007', 5],
                    ['NO', 'F', '15072002', '17062001', 8],
                    ['YES', 'I', '24092006', '03112003', 2],
                    ['YES', 'A', '22082010', '03012001', 9],
                    ['YES', 'I', '15072016', '30092005', 7],
                    ['YES', 'Y', '08111999', '02022006', 3],
                    ['NO', 'V', '04012016', '10061996', 1],
                    ['NO', 'I', '21012003', '11022001', 6],
                    ['NO', 'P', '06041992', '30111993', 6],
                    ['NO', 'W', '30081992', '02012016', 6]]


    apply_async_with_callback(rows_to_parse, df)

在MultiProcessing中更新這樣的DataFrames不起作用:

dataf = dataf.append(new_row,ignore_index=True)

一方面,這是非常低效的(每個附加的O(n)所以總共為O(n ^ 2)。首選方法是在一次通過中將一些對象連接在一起。

另一方面,更重要的是,dataf沒有為每次更新鎖定,因此無法保證兩個操作不會發生沖突(我猜這是崩潰的python)。

最后,append沒有就位,所以一旦回調完成就丟棄變量dataf !! 並且不對父dataf進行任何更改。


我們可以使用MultiProcessing listdict 列表如果您不關心順序或dict,如果您這樣做(例如枚舉),因為您必須注意,這些值不是從異步中以明確定義的順序返回的。
(或者我們可以創建一個自己實現Lock的對象,請參閱Eli Bendersky 。)
因此,進行了以下更改:

df = pd.DataFrame(existing_data,columns=cols)
# becomes
df = pd.DataFrame(existing_data,columns=cols)
d = MultiProcessing.list([df])

dataf = dataf.append(new_row,ignore_index=True)
# becomes
d.append(new_row)

現在,一旦異步完成,您就擁有了DataFrames的MultiProcessing.list。 您可以連接這些(和ignore_index )以獲得所需的結果:

pd.concat(d, ignore_index=True)

應該做的伎倆。


注意:在每個階段創建newrow DataFrame也不會讓pandas一次性將列表列表直接解析為DataFrame。 希望這是一個玩具示例,你真的希望你的大塊能夠獲得MultiProcessing的勝利(我聽說50kb作為一個經驗法則......),一次一行永遠不會是一個在這里贏。


旁白:你應該避免在代碼中使用全局變量(如df),在函數中傳遞它們會更加清晰(在這種情況下,作為checker的參數)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM