팬더 적용 기능의 병렬화와 관련 하여이 질문의 더 일반적인 버전이 있습니다. 따라서 이것은 상쾌한 질문입니다 :)
먼저 , "패키지 된"솔루션을 요청한 이후 더 신속 하게 언급하고 싶습니다 . 팬더 병렬화에 관한 대부분의 SO 질문에 나타납니다.
그러나 .. 나는 여전히 몇 년 동안 DataFrame을 사용한 후에도 100 % 병렬화 솔루션 (주로 적용 함수)을 찾지 못했기 때문에 항상 내 개인 코드를 공유하고 싶습니다 . 수동 "코드.
덕분에 (이론적으로) DataFrame 메서드를 이름으로 지원하는 것이 더 일반적이었습니다 (따라서 isin, apply 등의 버전을 유지할 필요가 없습니다.)
파이썬 2.7과 3.6을 모두 사용하여 "isin", "apply"및 "isna"함수에서 테스트했습니다. 20 줄 미만이며 "subset"및 "njobs"와 같은 팬더 명명 규칙을 따릅니다.
또한 "isin"에 대한 dask 등가 코드와 시간 비교를 추가 했으며이 요점보다 ~ X2 배 느려 보입니다.
그것은 두 가지 기능을 포함합니다 :
df_multi_core- 이것이 당신이 부르는 것입니다. 받아들입니다 :
- df 객체
- 호출하려는 함수 이름
- 함수를 수행 할 수있는 열의 하위 집합 (시간 / 메모리 감소에 도움이 됨)
- 병렬로 실행할 작업 수 (-1 또는 모든 코어에서 생략)
- 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