Excel & IT Info

아이엑셀러 닷컴, 엑셀러TV

Python

파이썬으로 Excel 파일을 읽으시나요? 여기 빠른 방법이 있습니다

권현욱(엑셀러) 2024. 7. 6. 18:37
반응형

들어가기 전에

파이썬으로 다양한 작업을 하다 보면 Excel 또는 CSV 형식으로 정보를 공유하는 것을 선호하는 경우가 많기 때문에 Excel 파일과 자주 상호 작용하여 데이터를 관리합니다. 그러나 Excel 파일을 처리할 때 Python이 눈에 띄게 느려질 수 있습니다. 파이썬에서 데이터를 로딩하는 5가지 방법을 소개합니다.

권현욱(엑셀러) | 아이엑셀러 닷컴 대표 · Microsoft Excel MVP · Excel 솔루션 프로바이더 · 작가

이미지: 아이엑셀러 닷컴

 

※ 이 글은 아래 기사 내용을 토대로 작성되었습니다만, 필자의 개인 의견이나 추가 자료들이 다수 포함되어 있습니다.


  • 원문: Do You Read Excel Files with Python? There is a 1000x Faster Way
  • URL: https://python.plainenglish.io/do-you-read-excel-files-with-python-there-is-a-1000x-faster-way-72a15964d30a

사전 준비

각각 20,000개의 행과 25개의 열로 구성된 총 70MB의 Excel 파일 10개를 로드해야 한다고 가정해 보겠습니다. 이 시나리오는 분석을 위해 SAP와 같은 ERP 시스템에서 Python으로 트랜잭션 데이터를 전송할 때 흔히 볼 수 있는 시나리오입니다. 먼저 이 더미 데이터를 생성하고 필요한 라이브러리를 가져와서 환경을 설정합니다.

 

import pandas as pd
import numpy as np
from joblib import Parallel, delayed
import time

for file_number in range(10):
    values = np.random.uniform(size=(20000,25))
    pd.DataFrame(values).to_csv(f"Dummy {file_number}.csv")
    pd.DataFrame(values).to_excel(f"Dummy {file_number}.xlsx")
    pd.DataFrame(values).to_pickle(f"Dummy {file_number}.pickle")

 

방법 1. Pandas를 사용하여 Excel 파일 로드하기

Excel 파일을 로드하는 가장 간단한 방법부터 시작하겠습니다. Pandas 데이터 프레임을 초기화하고 여기에 각 Excel 파일을 순차적으로 추가하겠습니다. 이 접근 방식은 여러 소스의 데이터를 분석을 위해 단일 구조로 컴파일하는 명확하고 직접적인 방법을 제공합니다.

start = time.time()
df = pd.read_excel("Dummy 0.xlsx")
for file_number in range(1,10):
    df.append(pd.read_excel(f"Dummy {file_number}.xlsx"))
end = time.time()
print("Excel:", end - start)

 

실행하는 데 약 50초가 걸립니다. 꽤 느립니다.

Excel 파일을 CSV 형식으로 변환한 후에는 로딩 시간이 0.63초로 크게 줄어들어 이전보다 10배 가까이 빨라졌습니다. Python은 일반적으로 Excel 파일보다 CSV 파일을 훨씬 빠르게 처리하며, 최대 100배까지 빠릅니다. 따라서 CSV를 사용하는 것은 대용량 데이터 세트를 처리하는 데 매우 효율적인 전략이 될 수 있습니다.

그러나 한 가지 주목할 만한 단점은 CSV 파일은 일반적으로 .xlsx 파일에 비해 파일 크기가 더 크다는 것입니다. 예를 들어, 이 예에서 CSV 파일은 각각 9.5MB인 반면, .xlsx 파일은 6.4MB에 불과합니다.

방법 2: 더 스마트한 Pandas 데이터프레임 생성

데이터 로딩 프로세스를 더욱 개선하기 위해 Pandas 데이터프레임 생성 방식을 최적화할 수 있습니다. 시간이 많이 소요될 수 있는 기존 데이터프레임에 각 파일을 직접 추가하는 대신 다음과 같이 하면 됩니다.

  1. 각 Excel 또는 CSV 파일을 별도의 데이터프레임에 로드합니다.
  2. 이러한 데이터프레임을 목록에 저장합니다.
  3. 마지막으로 목록에 있는 모든 데이터프레임을 하나의 데이터프레임으로 연결합니다.


이 방법은 데이터프레임을 반복적으로 확장할 때 발생하는 오버헤드를 줄여주기 때문에 일반적으로 각 파일을 증분적으로 추가하는 것보다 빠릅니다.

start = time.time()
df = []
for file_number in range(10):
    temp = pd.read_csv(f"Dummy {file_number}.csv")
    df.append(temp)
df = pd.concat(df, ignore_index=True)
end = time.time()
print("CSV2:", end - start)

 

로드 시간이 약간 단축되었습니다. 제 경험에 비추어 볼 때, 이 기술은 일반적으로 100MB가 훨씬 넘는 대용량 데이터 프레임을 처리할 때 특히 유용합니다.

방법 3: Joblib으로 CSV 가져오기 병렬화하기

로딩 프로세스를 더욱 신속하게 처리하려면 여러 파일을 병렬로 가져오는 것을 고려해 보세요. 10개의 파일을 각각 순차적으로 로드하는 대신 동시에 병렬로 로드할 수 있습니다.

이 접근 방식은 파이썬에서 병렬 처리를 간소화하는 `joblib` 라이브러리의 기능을 활용합니다. joblib`을 사용하면 파일 로딩 작업을 여러 코어 또는 스레드에 분산하여 전체 로드 시간을 크게 줄일 수 있습니다.

start = time.time()
def loop(file_number):
    return pd.read_csv(f"Dummy {file_number}.csv")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("CSV//:", end - start)

 

싱글 코어 버전에 비해 속도가 두 배로 빨라졌습니다. 하지만 코어 수를 늘린다고 해서 성능이 선형적으로 확장되는 것은 아니라는 점에 유의해야 합니다. 예를 들어 M1 칩이 탑재된 Mac Air에서 8개의 코어를 사용했을 때 속도가 8배가 아니라 2배로 증가했습니다.

Joblib을 사용한 Python의 간단한 병렬화

Joblib은 병렬 처리를 위해 설계된 간단한 Python 라이브러리입니다. 목록 이해와 비슷하게 작동하지만 중요한 차이점이 있습니다. 각 반복이 별도의 스레드에서 실행된다는 점입니다. 이 접근 방식을 사용하면 작업을 동시에 처리할 수 있습니다. 이를 구현하는 방법은 다음과 같습니다.

def loop(file_number):
    return pd.read_csv(f"Dummy {file_number}.csv")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))

#equivalent to
df = [loop(file_number) for file_number in range(10)]

 

방법 4: 피클 파일 활용

더욱 빠른 데이터 저장 및 검색 프로세스를 원한다면 피클(Pickle) 파일을 사용해 보세요. 피클은 객체를 직렬화 및 역직렬화하기 위해 설계된 Python 전용 포맷으로, .csv 파일에 비해 데이터를 더 빠르게 로드할 수 있습니다.

하지만 피클 파일은 사람이 읽을 수 없다는 단점이 있습니다. .csv 파일과 달리 피클 파일은 텍스트 편집기나 스프레드시트 프로그램에서 열어 내용을 직접 보거나 편집할 수 없습니다.

start = time.time()
def loop(file_number):
    return pd.read_pickle(f"Dummy {file_number}.pickle")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("Pickle//:", end - start)

 

처리 시간을 80% 단축하는 데 성공했습니다!

전반적으로 피클 파일로 작업하는 것이 .csv 파일을 사용하는 것보다 훨씬 빠릅니다. 하지만 피클 파일은 일반적으로 하드 드라이브의 저장 공간을 더 많이 차지합니다(이 예에서는 그렇지 않지만).

실제로 시스템에서는 일반적으로 데이터를 피클 형식으로 직접 내보내지 않습니다. 다음 시나리오에서는 피클 파일을 사용하는 것이 좋습니다.

1. 내부 Python 사용: Python 프로세스에서 데이터를 저장하고 Excel이나 기타 비 Python 환경에서 열 필요가 없는 경우, 데이터 프레임을 피클 파일로 저장하세요. 이는 Python 스크립트나 애플리케이션 내에서 재사용하려는 데이터에 이상적입니다.

2. 잦은 파일 액세스: 동일한 파일을 반복적으로 로드하는 경우, 최초 로드 후 피클 파일로 저장하는 것이 효율적입니다. 향후 프로세스에서는 느린 .csv 로드 프로세스를 건너뛰고 피클 파일에서 직접 로드할 수 있습니다.

예시: 매월 업데이트되는 트랜잭션 데이터를 관리하는 경우, 첫 번째 로드 후 매월의 데이터를 .csv에서 .pickle로 변환할 수 있습니다. 이렇게 하면 피클 형식의 과거 데이터에 빠르게 액세스하여 매달 새로운 데이터가 도착할 때마다 워크플로를 간소화할 수 있습니다.

 

보너스: Excel 파일을 병렬로 로드하기

Excel 파일을 받아 직접 작업해야 하는 상황에 처한 경우에도 병렬 처리를 적용하여 효율성을 높일 수 있습니다. 다른 형식과 마찬가지로 `joblib` 라이브러리를 사용하여 이러한 파일을 병렬로 로드할 수 있습니다.

이를 구현하려면 특별히 Excel 파일을 처리하도록 루프 내에서 함수를 조정해야 합니다. 이 수정에는 Excel 파일을 로드하도록 설계된 함수를 사용한 다음 `joblib`를 사용하여 이러한 작업을 여러 프로세서에 분산하는 것이 포함됩니다. 이 방법을 사용하면 여러 Excel 파일을 동시에 로드하는 데 걸리는 시간을 크게 줄일 수 있습니다.

start = time.time()
def loop(file_number):
    return pd.read_excel(f"Dummy {file_number}.xlsx")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("Excel//:", end - start)

 

로딩 시간을 70% 단축하여 50초에서 단 13초로 단축했습니다. 또한 이 병렬 로딩 프로세스를 활용하여 피클 파일을 즉시 생성할 수 있습니다. 이렇게 하면 다음에 이러한 파일을 로드해야 할 때 피클 파일이 제공하는 훨씬 빠른 로드 시간을 활용하여 거의 즉각적으로 데이터에 액세스할 수 있습니다. 이 방법은 초기 로딩 프로세스를 최적화할 뿐만 아니라 향후 동일한 데이터 세트와의 상호 작용도 간소화합니다.

마치며

다양한 데이터 로드 방법을 통해 효율성을 크게 개선하여 대용량 데이터 세트를 처리하는 데 걸리는 시간을 단축했습니다.

  • Excel 파일: 처음에는 로드하는 데 50초가 걸렸습니다.
  • CSV 파일: 0.63초로 개선되었습니다.
  • 더욱 스마트해진 CSV 로딩: 0.62초로 더욱 개선되었습니다.
  • 병렬 CSV 로드: 0.34초로 단축되었습니다.
  • 병렬 피클 로딩: 10분의 1초도 안 되는 0.07초로 대폭 단축되었습니다.
  • 병렬 Excel 로딩: 13.5초로 단축되었습니다.

 

이러한 결과는 파일 형식을 최적화하고 병렬 처리를 활용하여 Python에서 데이터 로딩 작업의 성능을 향상시키는 이점을 강조합니다.

Excel과 VBA의 모든 것 아이엑셀러 닷컴 · 강사들이 숨겨 놓고 보는 엑셀러TV