Python 数据帧的多处理写入

Python 数据帧的多处理写入,python,multithreading,python-2.7,pandas,multiprocessing,Python,Multithreading,Python 2.7,Pandas,Multiprocessing,因此,我试图用下面的代码读取一个列表列表,并通过名为checker的函数将其放入,然后让log\u result处理函数checker的结果。我尝试使用多线程来实现这一点,因为变量名rows\u to\u parse实际上有数百万行,所以使用多个内核应该会大大加快这个过程 目前的代码无法工作,导致Python崩溃 我的关注和问题: 想要保存在变量df中的现有df来维护 索引整个过程,否则将得到log\u结果 不清楚哪一行需要更新 我很确定apply\u async不合适 多处理函数来执行此任务,

因此,我试图用下面的代码读取一个列表列表,并通过名为
checker
的函数将其放入,然后让
log\u result
处理函数
checker
的结果。我尝试使用多线程来实现这一点,因为变量名
rows\u to\u parse
实际上有数百万行,所以使用多个内核应该会大大加快这个过程

目前的代码无法工作,导致Python崩溃

我的关注和问题:

  • 想要保存在变量
    df
    中的现有df来维护 索引整个过程,否则将得到
    log\u结果
    不清楚哪一行需要更新
  • 我很确定
    apply\u async
    不合适 多处理函数来执行此任务,因为我相信 计算机读取和写入df的顺序可能会损坏它
  • 我认为可能需要设置一个队列来写入和读取
    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)
    

    在多处理中这样更新数据帧是行不通的:

    dataf = dataf.append(new_row,ignore_index=True)
    
    首先,对于每个附加,这是非常低效的(O(n),所以总共是O(n^2)。首选的方法是在一次过程中将一些对象连接在一起

    另一方面,也是更重要的一点,dataf并没有为每个更新锁定,所以不能保证两个操作不会冲突(我猜这是在破坏python)

    最后,append不起作用,因此一旦回调完成,变量
    dataf
    将被丢弃!!并且不会对父变量
    dataf
    进行任何更改


    如果您不关心顺序,我们可以使用或.list;如果您关心顺序,我们可以使用dict(例如枚举),因为您必须注意,值不是以定义良好的顺序从异步返回的。
    (或者我们可以创建一个实现自身锁定的对象,请参见。)
    因此,进行了以下更改:

    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)
    
    现在,一旦异步完成,您就有了一个数据帧的MultiProcessing.list。您可以对这些数据帧进行压缩(和
    忽略\u index
    )以获得所需的结果:

    pd.concat(d, ignore_index=True)
    
    我们应该做到这一点


    注意:在每个阶段创建newrow数据帧的效率也低于让pandas一次性将列表直接解析到数据帧。希望这是一个玩具示例,您真的希望您的数据块非常大,以便通过多处理获得胜利(我听说50kb是一个经验法则…)在这里,一次吵架永远不会是一场胜利



    旁白:您应该避免在代码中使用全局变量(如df),在函数中传递它们(在本例中,作为checker的参数)要干净得多。

    还有什么:#不匹配,请为它指定写入df应该执行的参数?我想如果
    返回[a,b,c,d,e]
    您的代码实际上会完成,但您会有其他问题,您也从来没有在任何地方使用过dataf谢谢您指出,我已经修改了代码。因此
    [a,b,c,d,e]
    会写入函数
    log\u result
    中的df中
    部分(log\u result,dataf=dfr)
    log\u结果的签名不匹配
    如果不重新分配数据帧并且从不向同一位置写入两次,从多个线程同时向其写入是否安全?这在多处理上应该可以。list/dict,它处理锁定,因此是安全的。