본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] Pandas 데이터 메모리 80% 절감 방법 : float64를 float16 및 int8로 전환하는 해결책과 7가지 사례

by Papa Martino V 2026. 4. 26.
728x90

Pandas 데이터 메모리 80% 절감 방법
Pandas 데이터 메모리 80% 절감 방법

데이터 사이언티스트의 필수 역량, 메모리 프로파일링과 다운캐스팅(Downcasting) 완벽 가이드


1. Pandas 기본 데이터 타입의 함정: 왜 메모리가 부족할까?

파이썬의 Pandas 라이브러리는 데이터를 로드할 때 기본적으로 안전을 위해 가장 넓은 범위의 데이터 타입을 할당합니다. 정수는 int64, 실수는 float64가 기본값입니다. 하지만 실무에서 다루는 데이터의 범위를 생각해보면 이는 엄청난 낭비입니다.

예를 들어, 0부터 100 사이의 점수 데이터를 저장하는 데 64비트(8바이트)를 사용하는 것은, 작은 사과 하나를 담기 위해 대형 컨테이너를 빌리는 것과 같습니다. 이를 8비트(1바이트) int8로 최적화하면 메모리 사용량을 즉시 1/8로 줄일 수 있습니다. 본 글에서는 데이터의 정밀도를 유지하면서도 메모리 효율을 극대화하는 실무 테크닉을 다룹니다.

2. 데이터 타입별 메모리 점유 및 표현 범위 비교

각 데이터 타입이 메모리에서 차지하는 비중과 수용 가능한 수치 범위를 비교 분석하였습니다. 이 표를 통해 데이터의 성격에 맞는 최적의 타입을 선택할 수 있습니다.

데이터 타입 메모리 점유 (바이트) 최소값 최대값 비고
float64 8 Bytes -1.79e+308 1.79e+308 Pandas 기본 실수형
float32 4 Bytes -3.40e+38 3.40e+38 대부분의 ML 모델 권장
float16 2 Bytes -65500 65500 정밀도 손실 주의 필요
int64 8 Bytes -2^63 2^63 - 1 Pandas 기본 정수형
int32 4 Bytes -2,147,483,648 2,147,483,647 20억 단위 데이터 가능
int16 2 Bytes -32,768 32,767 날짜 연도, 온도 등에 적합
int8 1 Byte -128 127 범주형 인덱스, 낮은 점수

3. 실무 즉시 적용 가능한 최적화 Example (7가지)

대용량 DataFrame을 효율적으로 관리하기 위한 구체적인 파이썬 코드 예제입니다.

#1. 전체 메모리 사용량 프로파일링 함수

최적화 전후의 성과를 측정하기 위해 실제 메모리 점유량을 계산하는 도구가 필요합니다.

import pandas as pd
import numpy as np

def mem_usage(pandas_obj):
    if isinstance(pandas_obj, pd.DataFrame):
        usage_b = pandas_obj.memory_usage(deep=True).sum()
    else: # Series인 경우
        usage_b = pandas_obj.memory_usage(deep=True)
    usage_mb = usage_b / 1024 ** 2 # MB 단위 변환
    return "{:03.2f} MB".format(usage_mb)

# 임의의 대형 데이터프레임 생성
df = pd.DataFrame(np.random.rand(1000000, 5), columns=['A', 'B', 'C', 'D', 'E'])
print(f"초기 메모리: {mem_usage(df)}")
        

#2. 정수형 데이터 자동 다운캐스팅 (to_numeric)

값의 범위를 자동으로 계산하여 가장 작은 정수 타입으로 변환합니다.

# 정수형 컬럼 예시 (ID, 나이 등)
df['Age'] = np.random.randint(0, 100, size=1000000)

# 'integer' 타입으로 최대한 다운캐스팅
df['Age'] = pd.to_numeric(df['Age'], downcast='integer')

print(f"Age 컬럼 타입: {df['Age'].dtype}") # int8로 변환됨
        

#3. 실수형 데이터 정밀도 조정 (float64 -> float32/16)

딥러닝이나 대규모 통계 분석에서 64비트 정밀도가 필요하지 않은 경우 메모리를 절반 이상 아낄 수 있습니다.

# float64를 float32로 변환 (메모리 50% 절감)
df['A'] = df['A'].astype(np.float32)

# 아주 작은 범위의 실수라면 float16 고려
df['B'] = df['B'].astype(np.float16)

print(f"최적화 후 메모리: {mem_usage(df[['A', 'B']])}")
        

#4. 자동 최적화 루프 스크립트 (실무 추천)

모든 컬럼을 순회하며 데이터 유실 없이 최저 메모리 타입을 할당하는 자동화 코드입니다.

def reduce_mem_usage(df):
    for col in df.columns:
        col_type = df[col].dtype
        if col_type != object:
            c_min = df[col].min()
            c_max = df[col].max()
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                # ... 중략 (int32, int64 처리)
            else:
                df[col] = df[col].astype(np.float32) # 일반적인 실수형 최적화
    return df

df_optimized = reduce_mem_usage(df)
        

#5. Object 타입을 Category 타입으로 변환

중복되는 문자열이 많은 컬럼(예: 시도명, 등급)은 object 대신 category를 사용하면 드라마틱한 효과를 봅니다.

df['City'] = ['Seoul', 'Busan', 'Incheon', 'Daegu'] * 250000

# 변환 전후 메모리 비교
print(f"Object 메모리: {mem_usage(df['City'])}")
df['City'] = df['City'].astype('category')
print(f"Category 메모리: {mem_usage(df['City'])}")
        

#6. Sparse 데이터 구조 활용 (희소 행렬)

대부분의 값이 0이나 NaN인 경우, 실제 데이터가 있는 위치만 저장하여 메모리를 아낍니다.

# 99%가 0인 데이터
sparse_data = np.zeros(1000000)
sparse_data[0] = 1
df_sparse = pd.Series(sparse_data).astype(pd.SparseDtype("float", 0))

print(f"Sparse 메모리: {mem_usage(df_sparse)}")
        

#7. 파일 로드 시 데이터 타입 지정 (read_csv dtype)

데이터를 읽어온 뒤 바꾸는 것이 아니라, 처음부터 낮은 사양으로 읽어 메모리 폭발을 방지합니다.

# CSV 로드 시 딕셔너리로 타입 사전 정의
dtype_dict = {'Age': 'int8', 'Score': 'float32', 'Grade': 'category'}
# df = pd.read_csv('large_data.csv', dtype=dtype_dict)
        

4. 독창적인 최적화 인사이트: 정밀도와 성능의 트레이드오프

단순히 메모리를 줄이는 것이 정답은 아닙니다. float16은 표현 가능한 숫자가 약 65,500까지이므로, 누적 합산(sum)이나 평균 계산 시 수치가 오버플로우(Overflow)되어 inf가 되거나 미세한 오차가 발생할 수 있습니다. 따라서 핵심적인 해결책은 '분석 목적'에 따른 차등 적용입니다. 머신러닝 학습 피처로 사용할 때는 float32를, 단순히 라벨링이나 단순 통계를 낼 때는 int8이나 int16을 사용하는 전략적 선택이 전문적인 데이터 핸들링의 차이를 만듭니다.


내용 출처 및 참고 자료:

  • Pandas Official Documentation: "Memory Usage"  
  • NumPy Documentation: "Data types" 
  • High Performance Python by Micha Gorelick and Ian Ozsvald (O'Reilly Media)
  • Python Data Science Handbook by Jake VanderPlas
728x90