Pandas.DataFrame.isin'i paralel olarak çalıştırmanın basit bir yolu var mı?


25

DataFrame.isinBirkaç bin belirli sayfanın her biri için bireysel kullanıcıların kayıtlarını "beğenen" facebook listelerinde arama yaparak, pandaların işlevini yoğun kullanan bir modelleme ve puanlama programım var . Bu, programlamanın en zaman alan kısmı, modelleme veya puanlama parçalarından çok, sadece geri kalanı eşzamanlı olarak birkaç düzine çalıştırırken sadece bir çekirdekte çalıştığı için.

Veri çerçevesini elle parçalara ayırabileceğimi ve işlemi paralel olarak çalıştırabileceğimi bilmeme rağmen, bunu otomatik olarak yapmanın basit bir yolu var mı? Başka bir deyişle, kolayca devredilen bir işlemi yürüttüğümü ve otomatik olarak dağıttığımı fark edecek bir paket var mı? Belki de bu çok fazla şey istiyor, ama Python'da zaten mevcut olan şey yüzünden geçmişte yeterince şaşırdım, bu yüzden sormaya değer olduğunu düşünüyorum.

Bunun nasıl başarılabileceğine ilişkin başka öneriler (bazı sihirli tek boynuzlu at paketleri tarafından olmasa bile) da memnuniyetle karşılanacaktır. Temel olarak, çözümü kodlamak için eşit bir zaman harcamaksızın çalışma başına 15-20 dakika tıraş etmenin bir yolunu bulmaya çalışıyorum.


Değer listeniz ne kadar büyük? Set olarak geçmeyi denediniz mi? Paralellik için Joblib ile ilgilenebilirsiniz. Kullanımı kolaydır ve hesaplamaları hızlandırabilir. Büyük veri parçalarıyla kullanın.
oao

Başka bir seçenek de sorununuzu bir birleşme olarak yeniden ele almak. Panda'lara katılanlar çok daha hızlı. Stackoverflow.com/questions/23945493/…
Brian Spiering

Yine bir başka seçenek de daha hızlı olan np.in1d'yi kullanmak stackoverflow.com/questions/21738882/fast-pandas-filtering
Brian Spiering

Yanıtlar:


8

Ne yazık ki, paralelleştirme henüz pandalarda uygulanmadı. Bu özelliğin geliştirilmesine katılmak istiyorsanız, bu github konusuna katılabilirsiniz .

Bu amaçla herhangi bir "sihirli tek boynuzlu at paketi" tanımıyorum, bu yüzden en iyi şey kendi çözümünüzü yazmanız olacak. Ancak, bunun için hala zaman harcamak istemiyorsanız ve yeni bir şeyler öğrenmek istiyorsanız - MongoDB'de yerleşik iki yöntemi deneyebilirsiniz (harita azaltma ve çerçeve oluşturma). Bakınız mongodb_agg_framework .




0

Pandalar üzerinde paralelleştirme ile ilgili bu sorunun daha yaygın bir sürümü var işlevi uygulayın - yani bu canlandırıcı bir soru :)

İlk , “paketlenmiş” bir çözüm istediğinizden bu yana kaygılanmaktan bahsetmek istiyorum ve pandaların paralelleşmesiyle ilgili çoğu SO sorusunda görünüyor.

Ama .. Yine de kişisel öz kodumu paylaşmak isterim, çünkü DataFrame ile birkaç yıl çalıştıktan sonra% 100 paralelleştirme çözümü asla bulamadım (esas olarak başvuru fonksiyonu için) ve her zaman benim için geri gelmek zorunda kaldım " manuel "kod.

Senin sayende (Teorik olarak) herhangi bir DataFrame yöntemini ismiyle desteklemeyi daha genel hale getirdim (böylece sürümleri isin, uygula, vb. İçin saklamana gerek kalmayacak).

Hem python 2.7 hem de 3.6 kullanarak "isin", "application" ve "isna" fonksiyonları üzerinde test ettim. 20 satırın altında ve ben "subset" ve "njobs" gibi kongre adındaki pandaları takip ettim.

Ayrıca "isin" için dask eşdeğer koduyla bir zaman karşılaştırması ekledim ve bu özlemden ~ X2 kat daha yavaş görünüyor.

2 işlev içerir:

df_multi_core - aradığınız kişi budur. Kabul eder:

  1. Df nesneniz
  2. Aramak istediğiniz işlev adı
  3. İşlevin gerçekleştirilebileceği sütun alt kümesi (zamanın / belleğin azaltılmasına yardımcı olur)
  4. Paralel olarak çalışacak işlerin sayısı (-1 veya tüm çekirdekler için ihmal)
  5. Df'nin işlevini kabul eden diğer herhangi bir kwargs ("eksen" gibi)

_df_split - bu, çalışan modülde global olarak konumlandırılması gereken dahili bir yardımcı işlevdir (Pool.map "yerleşime bağımlıdır"), aksi halde dahili olarak bulurdum.

işte bu benim özümden kod (orada daha fazla panda işlev testi ekleyeceğim):

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

Körük, doğal, çok çekirdekli öz ve dask performanslarını karşılaştıran bir paralelleştirilmiş isin için test kodudur . 8 fiziksel çekirdeğe sahip bir I7 makinede, X4 kat daha hızlandım. Gerçek verilerinde ne olduğunu duymayı çok isterim!

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

Ben bir dask karşılaştırma eklendi @Therriault isin- hızlı sonra (karşılaştırıldığında dask ~ X1.75 kez - kod parçacığı 'Işın' ile en etkili olduğu görünüyor applyancak o zaman% 5 daha hızlı got dask bu işlevin)
mork
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.