python pandasのDataFrameをいい感じにmultiprocessingで並列処理する

pandasのDataFrameに文字列データとかを入れてるとなんとなく並列処理したくなります。そんな時のTips

とりあえずデータを作る

import pandas as pd
import numpy as np
from multiprocessing import Pool
import multiprocessing

df = pd.DataFrame({
    'animal':['monkey','dog','monkey','cat','dog'],
    'count':[2,4,1,4,5]
})

df

データを等分割して並列化する

各行が独立していて、計算処理を分割した各行に実行したい場合。

numpyのarray_splitはDataFrameを入れても均等に分割してくれます。それを利用して均等にDataFrameを分割して並列化します。

今回は普通に各行のcountを3倍する計算を並列化してみます。

def split_parallel(df,num_split,map_func):
    p = Pool(multiprocessing.cpu_count())
    df_split = np.array_split(df,num_split)
    result = p.map(map_func,df_split)
    p.close()
    return pd.concat(result)

def map_count(df):
    df['count'] *=3
    return df

df = split_parallel(df,10,map_count)
df

データをキーごとに分割する

例えばanimalの種類ごとに並列化したい場合(map reduceによくある感じ)、下記のようにDataFrameを指定カラムの種類ごとに分割して並列化できます。

def key_parallel(df,column_split,map_func):
    p = Pool(multiprocessing.cpu_count())
    df_split = []
    for i,v in df[column_split].value_counts().iteritems():
        t = df[df[column_split]==i].copy()
        df_split.append(t)
    
    result = p.map(map_func,df_split)
    p.close()
    return pd.concat(result)

def map_count(df):
    df['count'] *=3
    return df

df = key_parallel(df,'animal',map_count)
df

 

各行を3倍する処理を並列化するというpandasのメソッドを使えば一発で終わりそうな処理を並列化してみましたがこれが複雑な自然言語処理とかになるとpandasの関数だけではまかなえなくなり、イテレーションすることになると思います。そんなときに処理をこんな感じで並列化すれば、格段に処理が早くなります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください