Існує більш поширена версія цього питання щодо паралелізації функцій застосування панд, тому це є освіжаючим питанням :)
По-перше , я хочу зазначити швидше, оскільки ви попросили "упаковане" рішення, і це з'являється у більшості запитань щодо паралелізації панд.
Але .. Я все-таки хотів би поділитися своїм особистим кодом суті, оскільки після кількох років роботи з DataFrame я ніколи не знаходив 100% -ного рішення для паралелізації (головним чином для функції застосування), і мені завжди доводилося повертатися за своїм " посібник "код.
Завдяки вам я зробив більш загальним підтримку будь-якого (теоретично) методу DataFrame за його назвою (тому вам не доведеться зберігати версії для isin, застосовувати тощо).
Я перевірив це на функціях "isin", "apply" та "isna", використовуючи і python 2.7 та 3.6. Це під 20 рядками, і я дотримувався панд, що називають умовами типу "підмножина" та "njobs".
Я також додав порівняння часу з дак-еквівалентом коду для "isin", і, здається, ~ X2 рази повільніше, ніж ця суть.
Вона включає 2 функції:
df_multi_core - це той, кого ви телефонуєте. Він приймає:
- Ваш об'єкт df
- Назва функції, яку ви хочете зателефонувати
- Підмножина стовпців, над якими може виконуватися функція (сприяє зменшенню часу / пам'яті)
- Кількість завдань, які потрібно виконати паралельно (-1 або опустіть для всіх ядер)
- Будь-які інші kwargs функції df приймає (наприклад, "вісь")
_df_split - це внутрішня допоміжна функція, яка повинна бути розміщена в глобальному масштабі на запущеному модулі (Pool.map - "залежно від місця розташування"), інакше я б знаходив її всередині.
ось код з моєї суті (я додам ще тестів на функцію панди):
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
Беллоу - це тестовий код для паралелізованого ісіна , який порівнює основну, багатоядерну суть і продуктивність дак. На машині I7 з 8 фізичними ядрами я досяг близько 4 разів прискорення. Я хотів би почути, що ви отримуєте на своїх реальних даних!
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