Чи існує прямий спосіб паралельного запуску pandas.DataFrame.isin?


25

У мене є програма моделювання та підрахунку балів, яка широко використовує DataFrame.isinфункцію панд, здійснюючи пошук по списках фейсбукових "схожих" записів окремих користувачів на кожну з кількох тисяч певних сторінок. Це найбільш трудомістка частина програми, більше, ніж моделювання чи забивання штук, просто тому, що вона працює лише на одному ядрі, а решта працює на кілька десятків одночасно.

Хоча я знаю, що я міг би вручну розбити кадр даних на шматки і паралельно запустити операцію, чи є якийсь простий спосіб зробити це автоматично? Іншими словами, чи є там якийсь пакет, який розпізнає, що я виконую операцію, яка легко делегується, і автоматично її розповсюджую? Можливо, це просить занадто багато, але в минулому я був досить здивований тим, що вже доступно в Python, тому я вважаю, що варто запитати.

Будь-які інші пропозиції щодо того, як це можна досягти (навіть якби не якийсь чарівний пакет єдинорога!), Також будуть вдячні. В основному, просто намагаються знайти спосіб голити 15-20 хвилин за цикл, не витрачаючи рівної кількості часу на кодування рішення.


Наскільки великий ваш список цінностей? Ви намагалися передати це як набір? Для паралелізму вас може зацікавити Йобліб. Він простий у використанні і може прискорити обчислення. Використовуйте його з великими фрагментами даних.
oao

Інший варіант - переосмислити свою проблему як приєднання. Приєднання набагато швидше в Pandas stackoverflow.com/questions/23945493/…
Brian Spiering

Ще один варіант - використовувати np.in1d, який також швидше stackoverflow.com/questions/21738882/fast-pandas-filtering
Brian Spiering

Відповіді:


8

На жаль, паралелізація ще не реалізована в пандах. Ви можете приєднатися до цього випуску github, якщо хочете взяти участь у розробці цієї функції.

Я не знаю жодного "чарівного пакета єдинорога" для цих цілей, тому найкраще буде написати власне рішення. Але якщо ви все ще не хочете витрачати час на це і хочете дізнатися щось нове - ви можете спробувати два методи, вбудовані в MongoDB (карту скорочення та рамки agg). Дивіться mongodb_agg_framework .


6

Я думаю, що найкраща ваша ставка - це розетка . Я вважаю це надзвичайно корисним і простим. Перевірте його методи панди .

Отримати його можна піп .


Я рекомендую отримати розетку, перейшовши безпосередньо на GitHub. Це гарантує отримання останньої версії. github.com/columbia-applied-data-science/rosetta
Ian Langmore


0

Існує більш поширена версія цього питання щодо паралелізації функцій застосування панд, тому це є освіжаючим питанням :)

По-перше , я хочу зазначити швидше, оскільки ви попросили "упаковане" рішення, і це з'являється у більшості запитань щодо паралелізації панд.

Але .. Я все-таки хотів би поділитися своїм особистим кодом суті, оскільки після кількох років роботи з DataFrame я ніколи не знаходив 100% -ного рішення для паралелізації (головним чином для функції застосування), і мені завжди доводилося повертатися за своїм " посібник "код.

Завдяки вам я зробив більш загальним підтримку будь-якого (теоретично) методу DataFrame за його назвою (тому вам не доведеться зберігати версії для isin, застосовувати тощо).

Я перевірив це на функціях "isin", "apply" та "isna", використовуючи і python 2.7 та 3.6. Це під 20 рядками, і я дотримувався панд, що називають умовами типу "підмножина" та "njobs".

Я також додав порівняння часу з дак-еквівалентом коду для "isin", і, здається, ~ X2 рази повільніше, ніж ця суть.

Вона включає 2 функції:

df_multi_core - це той, кого ви телефонуєте. Він приймає:

  1. Ваш об'єкт df
  2. Назва функції, яку ви хочете зателефонувати
  3. Підмножина стовпців, над якими може виконуватися функція (сприяє зменшенню часу / пам'яті)
  4. Кількість завдань, які потрібно виконати паралельно (-1 або опустіть для всіх ядер)
  5. Будь-які інші 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

@Therriault Я додав порівняння з дасками isin- здається, фрагмент коду є найбільш ефективним із 'isin' - ~ X1,75 рази швидше, ніж даск (порівняно з applyфункцією, яка отримала лише 5% швидше, ніж даск)
mork
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.