Pandas의 to_numeric 함수를 이용해 메모리 용량 줄이기


✔️ downcast 란?

pandas 의 to_numeric 함수에서 선택적으로 사용할 수 있는 파라미터이다.
정형 데이터에 data type를 지정해 가장 작은 버전으로 낮춰 메모리를 절약할 수 있다.

데이터는 컴퓨터 RAM 용량만큼 불러올 수 있는데, 대용량 데이터를 불러와서 분석하거나 모델을 만들기 위해서는 메모리를 효율적으로 사용할 수 있어야 한다.

downcast가 필요한 이유는 메모리 사용량을 절약해 더 많은 데이터를 불러오고 더 많은 데이터를 분석하기 위해서이다.

(1) data type

  Data type Description
0 bool Boolean (True or False) stored as a byte
1 int Platform integer (normally either int32 or int64)
2 int8 Byte (-128 to 127)
3 int16 Integer (-32768 to 32767)
4 int32 Integer (-2147483648 to 2147483647)
5 int64 Integer (-9223372036854775808 to 9223372036854775807)
6 uint8 Unsigned integer (0 to 255)
7 uint16 Unsigned integer (0 to 65535)
8 uint32 Unsigned integer (0 to 4294967295)
9 uint64 Unsigned integer (0 to 18446744073709551615)
10 float Shorthand for float64.
11 float16 Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
12 float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
13 float64 Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
14 complex Shorthand for complex128.
15 complex64 Complex number, represented by two 32-bit floats
16 complex128 Complex number, represented by two 64-bit floats


✔️ downcast 적용

(1) 데이터 기본구조

  • Survived, Pclass, SibSp, Parch 컬럼은 모두 최솟값이 0 이상, 최댓값이 10 이하로 구성되어있다.
    • 하지만 dtype을 보면 모두 int64
    • 즉, RAM이 불필요하게 많이 쓰이고 있다는 뜻
  • Age, Fare 컬럼도 기술통계값을 보면 float64로 사용하기엔 적절하지 않다.
import pandas as pd

df = pd.read_csv("data/titanic/train.csv", index_col="PassengerId")
# downcast 전 총 메모리 사용량을 KB 기준으로 before_dc 변수에 저장함
before_dc = df.memory_usage().sum() / 1024
# 데이터프레임의 수치형 변수에 대한 기술통계값 확인 
display(df.describe())
# 데이터프레임의 기본정보 확인
df.info()
df의 수치형 변수에 대한 기술통계(왼쪽), df의 요약 정보(오른쪽)


(2) 다운캐스팅(downcasting)

  • 데이터타입의 버전을 낮추는 일은 함수를 만들어서 각 컬럼별로 적용해보았다.
  • 정형 데이터의 dtype이 int/float로 구성되어 있어 dtype_downcast 함수에 int/float의 경우만 넣었다.
def dtype_downcast(data):
    
    # 데이터프레임의 전체 컬럼에 대해 downcast 적용
    for col in df.columns:
        # 컬럼별 데이터타입을 dtype_name 변수에 할당
        dtype_name = df[col].dtypes.name
        # dtype이 int로 시작하는 경우
        if dtype_name.startswith("int"):
            # 0이상의 값만 가지는 컬럼인 경우
            if df[col].min() >= 0:
                # 0과 양의 정수만 포함하는 uint로 전환
                df[col] = pd.to_numeric(df[col], downcast="unsigned")
            # 0이하의 값도 포함하는 컬럼인 경우
            else:
                # 음의 정수, 0, 양의 정수를 포함하는 int로 전환
                df[col] = pd.to_numeric(df[col], downcast="integer")
        # dtype이 float로 시작하는 경우
        elif dtype_name.startswith("float"):
            # 가장 작은 버전의 float 타입으로 전환
            df[col] = pd.to_numeric(df[col], downcast="float")
            
dtype_downcast(df)

# downcast 후 총 메모리 사용량을 KB 기준으로 after_dc 변수에 저장함
after_dc = df.memory_usage().sum() / 1024

(3) 결과 모니터링

>>> print(f"downcast 전 : {before_downcast:.1f}+ KB")
>>> print(f"downcast 후 : {after_downcast:.1f}KB")
>>> print(f"절약한 총 메모리 사용량 : {(before_downcast - after_downcast):.1f}KB")

downcast  : 83.5+ KB
downcast  : 52.2+ KB
절약한  메모리 사용량 : 31.3+ KB
downcast 전(왼쪽), 후(오른쪽) 데이터프레임 요약 정보


✔️ 마치며

Kaggle의 train.csv 파일의 데이터를 불러왔을 때, 메모리 사용량을 보면 83.5 +KB 인데 정형 데이터를 pandas의 to_numeric 함수를 사용하여 낮은 버전의 dtype으로 바꿈으로써 메모리 사용량을 52.2 +KB로 약 63% 줄여보았다.

정형 데이터의 범위에 비해 dtype으로 표현할 수 있는 숫자 범위가 크다면 downcast로 데이터 사용량을 절약할 수 있다.


✔️ Reference


👩🏻‍💻개인 공부 기록용 블로그입니다
오류나 틀린 부분이 있을 경우 댓글 혹은 메일로 따끔하게 지적해주시면 감사하겠습니다.

댓글남기기