pandas.DataFrame.isin을 병렬로 실행하는 간단한 방법이 있습니까?


25

DataFrame.isin팬더 의 기능을 많이 사용하는 모델링 및 스코어링 프로그램을 사용하여 수천 명의 특정 페이지 각각에 대해 개별 사용자의 페이스 북 "유사한"레코드 목록을 검색합니다. 이는 모델링 또는 스코어링 조각보다 프로그램에서 가장 시간이 많이 걸리는 부분입니다. 단순히 하나의 코어에서만 실행되고 나머지는 수십 개에서 동시에 실행되기 때문입니다.

수동으로 데이터 프레임을 청크로 분할하고 작업을 병렬로 실행할 수 있다는 것을 알고 있지만 자동으로 수행하는 간단한 방법이 있습니까? 즉, 내가 쉽게 위임 된 작업을 실행하고 자동으로 배포하고 있음을 인식하는 패키지가 있습니까? 아마도 그것은 너무 많이 요구하지만, 파이썬에서 이미 사용할 수있는 것에 대해 과거에 충분히 놀랐으므로 물어 볼 가치가 있다고 생각합니다.

이것이 어떻게 달성 될 수 있는지에 대한 다른 제안들도 있습니다 (마법의 유니콘 패키지가 아니더라도!). 주로 솔루션을 코딩하는 데 동일한 시간을 소비하지 않고 실행 당 15-20 분을 단축하는 방법을 찾으려고 노력했습니다.


값 목록이 얼마나 큽니까? 세트로 전달하려고 했습니까? 병렬 처리의 경우 Joblib에 관심이있을 수 있습니다. 사용하기 쉽고 계산 속도를 높일 수 있습니다. 많은 양의 데이터와 함께 사용하십시오.
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를 참조하십시오 .




0

팬더 적용 기능의 병렬화와 관련 하여이 질문의 더 일반적인 버전이 있습니다. 따라서 이것은 상쾌한 질문입니다 :)

먼저 , "패키지 된"솔루션을 요청한 이후 더 신속 하게 언급하고 싶습니다 . 팬더 병렬화에 관한 대부분의 SO 질문에 나타납니다.

그러나 .. 나는 여전히 몇 년 동안 DataFrame을 사용한 후에도 100 % 병렬화 솔루션 (주로 적용 함수)을 찾지 못했기 때문에 항상 내 개인 코드를 공유하고 싶습니다 . 수동 "코드.

덕분에 (이론적으로) DataFrame 메서드를 이름으로 지원하는 것이 더 일반적이었습니다 (따라서 isin, apply 등의 버전을 유지할 필요가 없습니다.)

파이썬 2.7과 3.6을 모두 사용하여 "isin", "apply"및 "isna"함수에서 테스트했습니다. 20 줄 미만이며 "subset"및 "njobs"와 같은 팬더 명명 규칙을 따릅니다.

또한 "isin"에 대한 dask 등가 코드와 시간 비교를 추가 했으며이 요점보다 ~ X2 배 느려 보입니다.

그것은 두 가지 기능을 포함합니다 :

df_multi_core- 이것이 당신이 부르는 것입니다. 받아들입니다 :

  1. df 객체
  2. 호출하려는 함수 이름
  3. 함수를 수행 할 수있는 열의 하위 집합 (시간 / 메모리 감소에 도움이 됨)
  4. 병렬로 실행할 작업 수 (-1 또는 모든 코어에서 생략)
  5. df의 함수가 받아들이는 다른 kwargs (예 : "axis")

_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

Bellow는 기본 멀티 코어 요지 및 성능을 비교하여 병렬화 된 isin에 대한 테스트 코드입니다 . 8 개의 물리적 코어가있는 I7 시스템에서 약 X4 배 속도가 향상되었습니다. 나는 당신이 당신의 실제 데이터에서 얻는 것을 듣고 싶습니다!

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

내가 가진 DASK 비교를 추가 @Therriault isin- 빨리 다음합니다 (비교 DASK ~ X1.75 시간 - 코드는 'ISIN'에 가장 효과적인 것 같다 apply단지 다음 5 % 빨라졌습니다 DASK 것을 기능)
mork
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.