차밍이
Pandas DataFrame 성능 빠르게하기 - apply말고 Vectorization쓰자 본문
목차
데이터 분석을 위해 Data Preprocessing 과정을 진행하는 과정을 필수적으로 거치게됩니다.
데이터 가공을 진행하다보면 여러 Column들을 연산하여 수정하거나 새로운 데이터를 만드는 과정을 수행합니다.
이러한 과정에서 데이터량이 많아짐에 따라 연산 과정이 점점 늦어지는 현상이 발생합니다.
for문 반복
혹은 itterator
를 사용한 방법은 비효율적인 방법이다.
보통 apply & applymap 등을 많이 이용해서 코드를 작성합니다.
그럼에도 데이터가 많아지니, 더 빠르게 계산할 수 있는 방법은 Numpy를 최대한 활용기 + Vectorization
입니다.
기본적으로 Numpy Array를 활용
단순한 연산도 Numpy Array를 활용하면 더욱 빨라집니다.
데이터프레임의 Series의 경우 .values
와 to_numpy()
를 사용해서 ndarray
형태로 데이터를 바꿀 수 있다.
단순한 판다스의 연산들도 ndarray
를 활용하면 연산 속도 개선이 가능하다.
테스트 데이터 생성
import numpy as np
import pandas as pd
data = [[np.random.randint(1_000_000) for _ in range(2)] for _ in range(1_000_000)]
df = pd.DataFrame(data, columns=['X', 'Y'])
기본 연산 속도 비교
(번외 참고) 메모리를 효율적으로 활용하려면 query를 사용
pandas
의 query는 df.loc[ pd.eval( … ) ]
와 동일한 결과를 가진다.
쿼리를 사용하면 numpy에 비해 속도 측면에서 성능이 떨어지지만 메모리 효율을 높일 수 있다.
다중 조건을 활용한 계산의 경우, 각각의 조건에 대한 연산을 진행한 후 마지막에 최종 논리 연산을 수행한다.
그러면 각각의 조건에 대한 연산 결과를 메모리에 저장하고 있어야한다.
데이터가 많은 경우 연산 결과를 저장에 어려움이 있을 수 있다.
query를 사용하면 각 row마다 헌 번에 모든 조건을 검사해 메모리를 효율적으로 사용한다.
조건식이 복잡하고 데이터가 클수록 더 좋은 효과를 가지게된다.
test 결과상에는 17.3ms로 ndarray를 활용한 것보다 2배 이상의 시간이 소요된 것을 볼 수 있다.
메모리를 위해 시간효율을 조금 양보해야하는 부분이다.
reference : https://yahwang.github.io/posts/85
Vectorization 함수 백터화 하기
numpy의 decorator를 사용해서 함수를 백터화 할 수 있습니다.
기존의 그냥 함수와 다르게 numpy 형태로 함수를 적용할 수 있도록 만들어줍니다.
import numpy as np
import time
def strange_calc(v):
return (1.8 * v + 32) / 7 ** 3 // 17 % 9
np.vectorize
def strange_calc_vectorized(v):
return (1.8 * v + 32) / 7 ** 3 // 17 % 9
start = time.perf_counter()
df['X'].apply(strange_calc)
df['Y'].apply(strange_calc)
print(time.perf_counter() - start)
start = time.perf_counter()
strange_calc_vectorized(df['X'])
strange_calc_vectorized(df['Y'])
print(time.perf_counter() - start)
>>>
0.6138590999998996
0.1986875999991753
단순히 apply
를 통해 함수를 적용하는 것과 비교했을 때 2배 이상 빨라진 것을 확인할 수 있습니다.
pandas
의 경우 최대한 numpy
의 vector 계산을 활용하면 전반적인 성능을 최대로 끌어낼 수 있습니다.
2019년에 PYCON에서 발표한 자료에 따르면 단순 for문과 비교해서 632배 속도가 증가했고
.apply 대비 218배 속도가 빨라진 것을 확인할 수 있었다고 합니다.
데이터가 많아지고 연산이 복잡해질수록 백터화한 계산과의 성능차이가 더욱더 벌어질 것이므로 적극적으로 활용하면 좋습니다!
'파이썬 > 기본 문법 정리' 카테고리의 다른 글
[Python] 파일 옮기기 복사하기 - shutil 모듈 move copy (0) | 2023.02.06 |
---|---|
[Python] SQL 데이터 Pandas DataFrame으로 불러오기 & 저장하기 (0) | 2023.01.31 |
[Python] SQlite3 DB에 데이터 저장 및 조회 (1) | 2023.01.28 |
[Python] 랜덤한 데이터로 DataFrame 만들기 (0) | 2023.01.26 |
[Python] 파일 및 폴더 디렉토리 삭제하는 법 총정리 (0) | 2022.12.13 |
[Python] datetime 모듈 날짜 시간 포맷 맞추기와 포맷 코드 종류 (0) | 2022.07.08 |
[Python] Pandas 판다스는 과연 빠른가 ? 속도확인 value_counts, unique, drop_duplicates (0) | 2022.06.29 |
[Python] 멀티 프로세싱 사용하기 - 멀티 프로세싱 적용을 위한 함수들 알아보자 (0) | 2022.06.08 |