데이터분석
pandas DataFrame join merge concat 연산 속도 비교
jaehwi0823
2021. 7. 30. 01:00
0. Intro
pandas DataFrame을 join해야하는 경우는 매우매우 빈번하다.
그래서 join 방법들을 모두 정리해볼까 한다.
# 준비한 데이터는 다음과 같음
print(raw.shape) # (9142946, 21)
print(address.shape) # (1396049, 11)
1. 단일 column 기준 join
한 개의 column을 기준으로 join하는 방법들과 성능은 다음과 같음
결론: join 할 때 index를 바로 지정하지 말자;;
# pd.merge 사용
%%timeit
merge_on = pd.merge(raw, address, how='left', left_on='CI', right_on='CI')
# 42.1 s ± 178 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# 데이터프레임.merge 사용
%%timeit
merge_on2 = raw.merge(address, how='left', left_on='CI', right_on='CI')
# 42.7 s ± 894 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# join 할 때 index 바로지정 & on 파라미터
%%timeit
join_on = raw.join(address.set_index('CI'), how='left', on='CI', rsuffix='_y')
# 41.3 s ± 372 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# join 할 때 index 바로지정
%%timeit
join_on2 = raw.set_index('CI').join(address.set_index('CI'), how='left', rsuffix='_y')
#1min 2s ± 741 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
2. 단일 index 기준 join
한 개의 index를 기준으로 join하는 방법들과 성능은 다음과 같음
# 일단 index 지정은 빠름~
%%timeit
address2 = address.set_index('CI')
raw2 = raw.set_index('CI')
# 1.48 s ± 29.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# pd.merge 사용
%%timeit
merge_index = pd.merge(raw2, address2, how='left', left_index=True, right_index=True)
# 58 s ± 323 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# join 사용
%%timeit
join_index = raw2.join(address2, how='left', rsuffix='_y')
# 57.7 s ± 255 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
join을 index로 할 수 있다면, pd.concat을 추가로 활용할 수 있다
하지만, unique index인 경우에만 가능하다.
# pd.concat 사용: unique index가 아니면 불가..
# %%
%%timeit
concat_index = pd.concat([raw2, address2], axis=1)
# InvalidIndexError: Reindexing only valid with uniquely valued Index objects
3. index를 sorting 하고 join
분명 index를 쓰면 더 빠르다고 했는데 이상해서 sorting을 먼저 해봤다.
(index가 빠름 출처: https://stackoverflow.com/questions/40860457/improve-pandas-merge-performance)
# 일단 정렬: 시간이 쫌 걸린다
%%timeit
address3 = address2.sort_index()
raw3 = raw2.sort_index()
# 22.1 s ± 178 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# sort 이후 merge
%%timeit
merge_index3 = raw3.merge(address3, how='left', left_index=True, right_index=True)
# 38.5 s ± 185 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# sort 이후 join
%%timeit
join_index2 = raw3.join(address3, how='left', rsuffix='_y')
# 38 s ± 102 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
4. 결론
그냥 생각나는 방식으로 쓰고,
join을 많이 반복하는 경우 미리 index 기준으로 sorting 해두자.
끝.