본문 바로가기
Python Code

데이터프레임을 엑셀로 변환시 메모리 에러가 발생하는 이유에 대하여.

by quantWhale 2024. 4. 5.
반응형

안녕하세요. 인천고래입니다.

 

데이터베이스를 사용하지 않고 시계열 데이터를 엑셀 파일로 관리하는 경우가 있는데요.

예를 들어 통합적인 관리를 하기 위해 개별적인 종목별 주가 데이터가 저장된 엑셀 파일을 모두 로드해서 하나의 데이터프레임에 저장한 뒤 엑셀 파일로 통합하는 경우가 있습니다.

 

이 때 각 종목의 데이터가 많은 경우 메모리 부족 (MemoryError) 에러가 발생이 될 수 있습니다.

일반적으로 데이터프레임은 메모리에 상주해 있는 데이터이고 엑셀로 저장을 할 때 추가적인 메모리를 사용하지 않아도 될 것 같은데 실제로는 추가적인 메모리를 필요로 함으로써 메모리가 부족한 현상이 발생되게 됩니다.

 

좀 더 자세히 말씀을 드리자면

데이터프레임을 엑셀 파일로 변환할 때 추가적인 메모리 사용이 발생하는 이유는 변환 과정에서 생기는 메모리 오버헤드 때문입니다.

 

여기에는 몇 가지 주요 요인이 있습니다:

1. 데이터 변환 및 서식 지정 데이터프레임을 엑셀 파일로 변환할 때, pandas와 openpyxl 같은 라이브러리는 내부적으로 데이터의 형식을 변경하고, 엑셀 파일에 맞게 서식을 지정합니다. 이 과정에서 원본 데이터프레임 외에 추가적인 메모리가 사용됩니다. 예를 들어, 날짜나 숫자 데이터를 엑셀에서 사용할 수 있는 형식으로 변환하거나, 셀 서식을 설정하는 등의 작업이 포함됩니다.

 

2. 임시 객체 생성 엑셀 파일로의 변환 과정에서는 원본 데이터 외에도 여러 임시 객체가 메모리에 생성될 수 있습니다. 예를 들어, pandas는 내부적으로 엑셀 파일을 생성하기 위해 데이터를 임시 버퍼에 저장하거나, openpyxl 객체를 생성하여 데이터를 관리할 수 있습니다. 이러한 임시 객체들도 메모리를 추가로 사용합니다.

 

3. 파일 쓰기 버퍼 실제 파일로 저장하는 과정에서는 파일 쓰기 버퍼가 사용됩니다. 이 버퍼는 디스크에 데이터를 효율적으로 쓰기 위해 메모리에 임시로 데이터를 저장하는 공간입니다. 특히, 대용량 데이터를 처리할 때는 이러한 버퍼링 과정이 메모리 사용량을 증가시킬 수 있습니다.

 

4. 라이브러리의 메모리 관리 방식 사용하는 라이브러리(pandas, openpyxl 등)의 내부 구현에 따라 메모리 관리 방식이 다를 수 있습니다. 일부 라이브러리는 메모리 효율성을 최적화하기 위해 설계되었지만, 데이터를 파일로 변환하는 과정에서는 필연적으로 추가 메모리가 필요할 수 있습니다.

 

이러한 이유로, 이미 메모리에 로드되어 있는 데이터프레임을 엑셀 파일로 변환하는 과정에서도 추가적인 메모리 사용이 발생할 수 있으며, 이는 메모리 오버헤드로 인해 MemoryError를 발생시킬 수 있습니다. 대용량 데이터를 처리할 때는 이러한 메모리 사용량을 고려하여 적절한 방법을 선택하는 것이 중요합니다.

 

그럼 아래와 같이 대용량의 데이터프레임을 엑셀 파일로 만들 때 발생하는 메모리 오류를 해결 방법은 없는 걸까요?

all_signals_df.to_excel(f"data/signal/081_all_signals_data_{today_date_str}.xlsx", index=True)

 

 

메모리 에러를 해결할 수 있는 방법은 아래와 같습니다.

        if len(all_signals_df) > 0:
            file_path = f"data/signal/081_all_signals_data_{today_date_str}.xlsx"
            # openpyxl Workbook 생성
            wb = Workbook()
            ws = wb.active

            # 엑셀 파일의 첫 번째 행에 컬럼명 추가
            ws.append(list(all_signals_df.columns))

            # all_signals_df의 각 행을 엑셀 파일에 추가
            for index, row in all_signals_df.iterrows():
                ws.append(list(row))

            # 엑셀 파일 저장
            wb.save(file_path)
            print("모든 종목에 대한 Signal 정보를 취합하였습니다.")

 

위와 같은 방식의 코드는 all_signals_df 데이터프레임의 각 행을 순회하며,

각 행의 데이터를 새로운 엑셀 파일의 행으로 추가합니다. 첫 번째 행에는 데이터프레임의 컬럼명을 추가합니다.

 

이 방식은 데이터프레임 전체를 한 번에 메모리에 로드하여 엑셀 파일로 저장하는 것이 아니라,

한 행씩 순차적으로 파일에 쓰므로 메모리 사용량을 줄일 수 있습니다.

 

이렇게 수정한 코드는 pandas의 to_excel() 메서드를 사용하는 것보다 메모리 사용량을 크게 줄이면서 대용량 데이터를 엑셀 파일로 저장할 때 유용합니다.

 

이번 글을 통해 엑셀로 변환시 메모리 부족 현상을 없애고 우회하여 엑셀로 저장하는 코드에 대해 알아보았습니다.

수고 하셨습니다.

감사합니다.

 

반응형
-

댓글