반응형

Pandas의 read_csv 함수의 느린 속도를 개선하는 방법을 다룹니다.



2022. 03. 11   최초작성



csv 파일을 하나 읽어서 작업할 때에는 Pandas의 read_csv 함수가 느리다는 것을 알지 못했는데 대량의 csv 파일을(정확히는 196,032개) 로드해보니 느리다는 것을 알 수 있었습니다. 



개선할 방법을 찾아보니 read_csv의 engine 아규먼트에 pyarrow를 지정하는 방법이 있었습니다. 앞에서 했던 196,032개의 csv 파일을 로드하는 시간이 3분에 1로 감소했습니다.  

 

df = pd.read_csv("large.csv", engine="pyarrow") 



속도는 빨라지지만 단점이 있다면 기존 read_csv와 완벽히 호환이 안되서 nrows 같은 아규먼트를 사용할 수 없습니다.

pyarrow를 사용하려면 pyarrow 패키지를 pip 명령으로 설치해야 합니다.




아래 링크에서 다운로드 받은 857.7MB의 Data8277.csv 파일을 로드하는 시간을 비교  테스트해봤습니다.

 

https://www3.stats.govt.nz/2018census/Age-sex-by-ethnic-group-grouped-total-responses-census-usually-resident-population-counts-2006-2013-2018-Censuses-RC-TA-SA2-DHB.zip?_ga=2.64023404.2121263669.1646980987-11651824.1646980987




테스트에 사용한 소스코드입니다.

 

import pandas as pd
import time


start = time.time()
df = pd.read_csv("Data8277.csv")
print('without pyarrow', time.time()-start)


start = time.time()
df = pd.read_csv("Data8277.csv", engine="pyarrow")
print('with pyarrow', time.time()-start)




실행 결과입니다.  pyarrow를 사용하여 2배 정도 빨라졌습니다. 사용한 csv 파일 크기나 개수에 따라 수치는 달라질 수 있습니다.

참고한 사이트의 테스트 결과에서는 더 큰 차이를 보여줍니다.

 

without pyarrow 5.526663064956665

with pyarrow 2.6792330741882324




nrows 아규먼트가 지원하지 않는 점을 고려하여 Pandas의 read_csv 대신에 Python 코드를 사용하여 같은 동작을 하는 코드 예제입니다.

테스트해보면 pandas의 read_csv를 사용하지 않은 코드가 더 빠릅니다.

 

import pandas as pd
import os
import time


path = './Training/'  


start = time.time()
for root, dirs, files in os.walk(path):
    for name in files:
        if name.endswith(".csv"):               

            df = pd.read_csv(os.path.join(root, name), header=None, skiprows=3, nrows=1)
            label = df[1]
            # print(label)

print('with read_csv', time.time()-start)



start = time.time()
for root, dirs, files in os.walk(path):
    for name in files:
        if name.endswith(".csv"):               
            with open(os.path.join(root, name), 'r', encoding="UTF-8") as fp:
                # 읽을 라인 지정, 라인번호가 0부터 시작하므로 4번째줄을 가져옴
                line_numbers = [3]

                lines = []
                for i, line in enumerate(fp):

                    if i in line_numbers:
                        lines.append(line.strip())
                    elif i > 4:
                        break

            label = int(lines[0].split(',')[-1])
            #print(label)         

print('without read_csv', time.time()-start)

 

 

 

참고

 

https://pythonspeed.com/articles/pandas-read-csv-fast/ 

 




반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts