Esiste una versione più comune di questa domanda per quanto riguarda la parallelizzazione sulla funzione di applicazione dei panda - quindi questa è una domanda rinfrescante :)
In primo luogo , voglio menzionare più rapidamente poiché hai chiesto una soluzione "pacchettizzata", e appare sulla maggior parte delle domande SO relative alla parallelizzazione dei panda.
Ma .. mi piacerebbe ancora condividere il mio codice personale per questo, dal momento che dopo diversi anni di lavoro con DataFrame non ho mai trovato una soluzione di parallelizzazione al 100% (principalmente per la funzione apply) e dovevo sempre tornare per il mio " manuale "codice.
Grazie a te ho reso più generico supportare qualsiasi metodo DataFrame (teoricamente) con il suo nome (quindi non dovrai conservare le versioni per isin, apply, ecc.).
L'ho provato sulle funzioni "isin", "apply" e "isna" usando sia Python 2.7 che 3.6. Ha meno di 20 righe e ho seguito la convenzione di denominazione dei panda come "subset" e "njobs".
Ho anche aggiunto un confronto temporale con il codice equivalente di Dask per "isin" e sembra ~ X2 volte più lento di questo senso.
Include 2 funzioni:
df_multi_core - questo è quello che chiami. Accetta:
- Il tuo oggetto df
- Il nome della funzione che desideri chiamare
- Il sottoinsieme di colonne su cui può essere eseguita la funzione (aiuta a ridurre il tempo / la memoria)
- Il numero di lavori da eseguire in parallelo (-1 o ometti per tutti i core)
- Qualsiasi altro kwarg accettato dalla funzione del df (come "axis")
_df_split - questa è una funzione di supporto interna che deve essere posizionata globalmente sul modulo in esecuzione (Pool.map è "dipendente dal posizionamento"), altrimenti lo localizzerei internamente.
ecco il codice dal mio succo (aggiungerò altri test di funzione panda lì):
import pandas as pd
import numpy as np
import multiprocessing
from functools import partial
def _df_split(tup_arg, **kwargs):
split_ind, df_split, df_f_name = tup_arg
return (split_ind, getattr(df_split, df_f_name)(**kwargs))
def df_multi_core(df, df_f_name, subset=None, njobs=-1, **kwargs):
if njobs == -1:
njobs = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes=njobs)
try:
splits = np.array_split(df[subset], njobs)
except ValueError:
splits = np.array_split(df, njobs)
pool_data = [(split_ind, df_split, df_f_name) for split_ind, df_split in enumerate(splits)]
results = pool.map(partial(_df_split, **kwargs), pool_data)
pool.close()
pool.join()
results = sorted(results, key=lambda x:x[0])
results = pd.concat([split[1] for split in results])
return results
Bellow è un codice di test per un'isina parallelizzata , che confronta le prestazioni native, multi-core e dask. Su una macchina I7 con 8 core fisici, ho ottenuto circa 4 volte la velocità. Mi piacerebbe sapere cosa ottieni sui tuoi dati reali!
from time import time
if __name__ == '__main__':
sep = '-' * 50
# isin test
N = 10000000
df = pd.DataFrame({'c1': np.random.randint(low=1, high=N, size=N), 'c2': np.arange(N)})
lookfor = np.random.randint(low=1, high=N, size=1000000)
print('{}\ntesting pandas isin on {}\n{}'.format(sep, df.shape, sep))
t1 = time()
print('result\n{}'.format(df.isin(lookfor).sum()))
t2 = time()
print('time for native implementation {}\n{}'.format(round(t2 - t1, 2), sep))
t3 = time()
res = df_multi_core(df=df, df_f_name='isin', subset=['c1'], njobs=-1, values=lookfor)
print('result\n{}'.format(res.sum()))
t4 = time()
print('time for multi core implementation {}\n{}'.format(round(t4 - t3, 2), sep))
t5 = time()
ddata = dd.from_pandas(df, npartitions=njobs)
res = ddata.map_partitions(lambda df: df.apply(apply_f, axis=1)).compute(scheduler='processes')
t6 = time()
print('result random sample\n{}'.format(res.sample(n=3, random_state=0)))
print('time for dask implementation {}\n{}'.format(round(t6 - t5, 2), sep))
--------------------------------------------------
testing pandas isin on (10000000, 2)
--------------------------------------------------
result
c1 953213
c2 951942
dtype: int64
time for native implementation 3.87
--------------------------------------------------
result
c1 953213
dtype: int64
time for multi core implementation 1.16
--------------------------------------------------
result
c1 953213
c2 951942
dtype: int64
time for dask implementation 2.88