차밍이

Pandas DataFrame 성능 빠르게하기 - apply말고 Vectorization쓰자 본문

파이썬/기본 문법 정리

Pandas DataFrame 성능 빠르게하기 - apply말고 Vectorization쓰자

2023. 1. 2. 19:55
반응형

목차

     

     

    데이터 분석을 위해 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배 속도가 빨라진 것을 확인할 수 있었다고 합니다.

    데이터가 많아지고 연산이 복잡해질수록 백터화한 계산과의 성능차이가 더욱더 벌어질 것이므로 적극적으로 활용하면 좋습니다!

     

    pycon 2019 영상

     

    반응형

    관련된 글 보기

    Comments