簡體   English   中英

如何並行化行方式 Pandas 數據幀的 apply() 方法

[英]How to parallelize the row wise Pandas dataframe's apply() method

我有以下代碼:

import pandas as pd
import time

def enrich_str(str):
        
    val1 = f'{str}_1'
    val2 = f'{str}_2'
    val3 = f'{str}_3'
    time.sleep(3)
    
    return val1, val2, val3
    
def enrich_row(passed_row):
    col_name = str(passed_row['colName'])
    my_string = str(passed_row[col_name])
    
    val1, val2, val3 = enrich_str(my_string)
    
    passed_row['enriched1'] = val1
    passed_row['enriched2'] = val2
    passed_row['enriched3'] = val3
    
    return passed_row


df = pd.DataFrame({'numbers': [1, 2, 3, 4, 5], 'colors': ['red', 'white', 'blue', 'orange', 'red']}, 
                  columns=['numbers', 'colors'])

df['colName'] = 'colors'

tic = time.perf_counter()
enriched_df = df.apply(enrich_row, col_name='colors', axis=1)
toc = time.perf_counter()

print(f"{df.shape[0]} rows enriched in {toc - tic:0.4f} seconds")

enriched_df

獲取 output dataframe 需要 15 秒,如下所示:

在此處輸入圖像描述

現在我想在我的機器上使用多個線程並行化豐富操作。 我探索了很多解決方案,例如Dasknumba ,但它們對我來說似乎都不是直截了當的。

然后我偶然發現了multiprocessing庫及其pool.imaps()方法。 所以我嘗試運行以下代碼:

import multiprocessing as mp

tic = time.perf_counter()
pool = mp.Pool(5)
result = pool.imap(enrich_row, df.itertuples(), chunksize=1)
pool.close()
pool.join()
toc = time.perf_counter()

print(f"{df.shape[0]} rows enriched in {toc - tic:0.4f} seconds")
result

大約需要 2 秒, result不是 Pandas dataframe。 我不知道我哪里錯了。

我建議您使用 pathos forkmultiprocessing ,因為它可以更好地處理數據幀的酸洗。 imap返回一個迭代器,而不是 DataFrame,因此您必須將其轉換回來:

def enrich_row(row_tuple):
    passed_row = row_tuple[1]
    col_name = str(passed_row['colName'])
    my_string = str(passed_row[col_name])
    
    val1, val2, val3 = enrich_str(my_string)
    
    passed_row['enriched1'] = val1
    passed_row['enriched2'] = val2
    passed_row['enriched3'] = val3
    
    return passed_row

df = pd.DataFrame({'numbers': [1, 2, 3, 4, 5], 'colors': ['red', 'white', 'blue', 'orange', 'red']}, 
                  columns=['numbers', 'colors'])

df['colName'] = 'colors'

from pathos.multiprocessing import Pool

tic = time.perf_counter()
result = Pool(8).imap(enrich_row, df.iterrows(), chunksize=1)
df = pd.DataFrame(result)
toc = time.perf_counter()

print(f"{df.shape[0]} rows enriched in {toc - tic:0.4f} seconds")
print(df)

請注意,我正在使用df.iterrows()它返回元組(row_number, row)的迭代器,所以我修改enrich_row來處理這種格式。

我接受了@albert 的回答,因為它適用於 Linux。 無論如何,我發現Dask 數據框的apply()方法非常簡單。 正如我在之前的評論中提到的,起初該操作不是在 120 行的數據集上並行執行的。 后來發現120行只用到了Dask dataframe的一個分區。 因此,進行重新分區以獲得所需的並行性就足夠了。 是一個使用 Dask 的代碼示例(它會引發一些奇怪的警告......)。

暫無
暫無

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

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