[Troubleshooting] 파이썬(Python) Pandas 대용량 엑셀/CSV 처리 중 MemoryError 완벽 해결 아키텍처

"5기가바이트짜리 로그 데이터를 Pandas로 읽어 들이는데, 컴퓨터 램(RAM)이 100%를 치더니 파이썬이 강제 종료되었습니다."

데이터 분석 실무자들이 파이썬(Python)의 Pandas 라이브러리를 찬양하다가 처음으로 배신감을 느끼는 순간이다. Pandas의 read_csv()read_excel() 함수는 데이터를 분석하기 위해 파일 전체를 컴퓨터의 메인 메모리(RAM)에 한 번에 올려버리는 구조를 띄고 있다. 만약 당신의 램 용량이 16GB인데, 읽어 들일 데이터가 5GB라면? Pandas는 내부적으로 데이터를 변환하고 인덱싱하는 과정에서 원본 용량의 3~5배에 달하는 메모리를 집어삼키며 결국 'MemoryError (메모리 초과)'를 뱉어내고 장렬히 전사한다.

이 에러를 만난 초보자들은 비싼 돈을 들여 컴퓨터 램을 64GB로 증설하거나 클라우드 서버 사양을 높인다. 하지만 진정한 데이터 아키텍트는 하드웨어를 돈으로 바르기 전에, 소프트웨어의 파이프라인을 최적화한다. 본 가이드에서는 대용량 데이터를 조각내어 처리하는 '청크(Chunk)' 아키텍처를 단호하게 제시한다.

1단계: 핵심 원인 분석 (In-Memory 연산의 한계)

Pandas는 빠르다. 그 빠른 속도의 비결은 모든 데이터를 메모리에 올려두고 연산(In-Memory)하기 때문이다. 하지만 빅데이터 시대에 수천만 행의 데이터를 한 번에 메모리에 올리는 것은 자살 행위다. 데이터베이스에서 쿼리를 날리듯, 필요한 만큼만 꺼내서 쓰고 버리는 스트리밍(Streaming) 방식의 접근이 필수적이다.

2단계: 완벽한 해결책 - Chunksize를 활용한 데이터 분할 처리

Pandas는 이미 대용량 처리를 위한 chunksize 파라미터를 제공하고 있다. 이 옵션을 사용하면 1천만 행의 데이터를 한 번에 읽지 않고, 10만 행씩 100번에 걸쳐 쪼개어 읽어 들인다. 메모리 점유율을 획기적으로 낮추면서도 모든 데이터에 대한 연산을 수행할 수 있다.

아래는 실무에서 대용량 데이터를 안전하게 필터링하고 병합할 때 사용하는 Python 트러블슈팅 코드다.

import pandas as pd

FILE_PATH = 'massive_log_data.csv'
CHUNK_SIZE = 100000  # 한 번에 메모리에 올릴 행(Row)의 수

def process_massive_data(file_path):
    # 빈 리스트를 생성하여 정제된 데이터 조각들을 담을 준비를 한다
    processed_chunks = []
    
    # chunksize를 지정하면 TextFileReader 객체(제너레이터)가 반환된다
    chunk_iterator = pd.read_csv(file_path, chunksize=CHUNK_SIZE)
    
    for i, chunk in enumerate(chunk_iterator):
        print(f"[{i+1}번째 청크 처리 중...] 메모리 최적화 가동")
        
        # 1. 불필요한 열(Column) 제거로 메모리 다이어트
        chunk = chunk[['date', 'user_id', 'action', 'revenue']]
        
        # 2. 필요한 조건만 필터링 (예: 결제 완료 액션만 추출)
        filtered_chunk = chunk[chunk['action'] == 'purchase']
        
        # 3. 데이터 타입 다운캐스팅 (float64 -> float32 등)으로 추가 메모리 확보
        filtered_chunk['revenue'] = pd.to_numeric(filtered_chunk['revenue'], downcast='float')
        
        # 4. 정제된 가벼운 조각만 리스트에 저장
        processed_chunks.append(filtered_chunk)
        
    # 모든 조각을 하나의 깔끔한 데이터프레임으로 병합
    final_dataframe = pd.concat(processed_chunks, ignore_index=True)
    print("대용량 데이터 병합 완료! MemoryError 방어 성공.")
    
    return final_dataframe

if __name__ == "__main__":
    df = process_massive_data(FILE_PATH)

3단계: 추가 최적화 (Data Type Downcasting)

청크 처리와 함께 반드시 병행해야 하는 것이 '데이터 타입 최적화(Downcasting)'다. Pandas는 숫자를 읽을 때 무조건 가장 무거운 64비트 타입(int64, float64)을 할당한다. 만약 회원 나이 데이터가 1부터 100 사이라면 8비트(int8)로도 충분하다. 위 코드의 주석 3번처럼 pd.to_numeric(downcast='float')를 습관적으로 적용하라. 이것만으로도 전체 메모리 사용량의 50% 이상을 가볍게 날려버릴 수 있다.

아키텍트의 시선 (Insight)

MemoryError는 컴퓨터가 고장 난 것이 아니라, 당신의 코드가 데이터의 무게를 감당할 만큼 유연하지 못하다는 시스템의 경고다. 모든 것을 한 번에 집어삼키려는 탐욕을 버리고, 데이터를 잘게 쪼개어 소화하는 청킹(Chunking) 파이프라인을 구축하라. 이는 단순히 에러를 피하는 것을 넘어, 한정된 컴퓨터 자원으로 무한한 데이터를 다루는 데이터 엔지니어링의 정수다.

댓글

이 블로그의 인기 게시물

[Troubleshooting] 504 Gateway Timeout 에러 완벽 방어: 파이썬(Python) Celery와 Redis 기반 비동기 백그라운드 아키텍처

[Troubleshooting] 리액트(React) & 뷰(Vue) SPA 웹사이트 GA4 페이지뷰 누락 완벽 해결 아키텍처

[Troubleshooting] AWS RDS 'Too Many Connections' 에러 완벽 방어: RDS Proxy 및 Connection Pool 아키텍처