이번 포스팅에서는 파이썬에서 발생할 수 있는 ParserError 해결 방법에 대해서 알아보겠습니다. 지난 번 포스팅에서는 빅데이터 분석 시 기초적이지만, 필수적인 데이터 encoding 형식을 확인하는 방법에 대해서 알아보았는데요.
데이터 encoding 형식을 확인한 후, 데이터 분석을 하기 위해 메모리 업로드 시 ParserError가 발생했습니다. 이번 포스팅에서는 데이터 파싱 시 발생할 수 있는 문제를 해결하는 방법에 대해서 알아보겠습니다.
파싱에 대한 자세한 설명은 파싱(Parsing) 이해하기를 참고하시면 됩니다.
ParserError 확인
데이터 encoding 형식을 확인하는 방법에서 확인된 에러를 다음과 같습니다.
import pandas as pd
csvStream = pd.read_csv("D:/big_data/big_data.csv", sep = ',', encoding = 'EUC-KR')
--------------------------------------------------------------------------------------
ParserError: Error tokenizing data. C error: Expected 970 fields in line 1965, saw 972
ParserError 내용을 살펴보면, 1,965 번째 데이터에서 문제가 생긴 것으로 보입니다. 데이터 열의 개수가 970개로 추정되는데, 972개의 열이 존재하는 것처럼 보인다는 내용입니다.
데이터 용량이 크지 않으면, 직접 더블 클릭하여 확인하면 되지만, 빅데이터에서는 불가능합니다. ParserError를 해결해야 합니다. 해결 방법에는 크게 3가지가 존재합니다.
ParserError 해결 방법
ParserError를 해결하는 방법은 크게 3가지 입니다.
잘못 파싱된 데이터 건너뛰기
제일 먼저 고려할 수 있는 해결 방법은 잘못 파싱된 데이터 행을 건너뛰는 방법입니다 (빅데이터 분석 시 다른 방법이 있는 지는 잘 모르겠네요. 아시는 분 있으시면 공유 부탁드립니다). pandas 라이브러리의 read_csv 함수에서 제공하는 옵션을 활용하면 됩니다.
이 옵션은 pandas 라이브러리의 버전에 따라 다릅니다.
error_bad_lines 옵션 (pandas 1.2.x 이하)
error_bad_lines 옵션은 bool 형태로, 기본값은 True 입니다.
이 옵션을 True로 설정하면, 잘못 파싱된 데이터가 있는 라인을 발견했을 때 오류 메시지를 출력하고 해당 라인을 무시하고 건너뜁니다.
만약 False로 설정하면, 오류 메시지 없이 잘못된 라인을 무시하고 계속해서 파일을 읽습니다.
on_bad_lines 옵션 (pandas 1.3.x 이상)
on_bad_lines는 error_bad_lines 옵션을 대체하여 도입된 옵션으로, 세 가지 옵션을 제공합니다.
- error: 잘못된 라인이 있을 경우 오류를 발생시키고 읽기 작업을 중단합니다. 이는 기존 error_bad_lines = True와 비슷합니다.
- warn: 잘못된 라인이 있을 경우 경고를 출력하고 그 라인을 건너뜁니다. 이 옵션은 error_bad_lines = Falsed와 유사하지만, 경고 문구를 제공합니다.
- skip: 잘못된 라인을 조용히 건너뛰고 아무런 경고나 오류를 발생시키지 않습니다.
ParserError 해결 후 빅데이터 메모리 업로드 재시도
빅데이터 처리를 위한 encoding 형식 확인 방법에서 발생한 ParserError를 해결하는 방법을 찾았습니다. 그럼 이 옵션을 활용하여 다시 한번 빅데이터를 메모리에 업로드 해보겠습니다.
import pandas as pd
csvStream = pd.read_csv("D:/big_data/big_data.csv", sep = ',', encoding = 'EUC-KR', error_bad_lines = False, header = None)
----------------------------------------------------------------------------------------------------------------------------
Skipping line 1965: expected 970 fields, saw 972
....
MemoryError: Unable to allocate 5.45 GiB for an array with shape (961, 760918) and data type int64
파싱에 문제가 있었던 데이터는 건너뛰기로 해결한 듯 보이지만, 또 다른 새로운 에러(MemoryError)가 발생했습니다. 이는 현재 사용중인 메모리에 데이터를 로드하기에는 메모리 용량이 작아 발생하는 에러입니다.
chunksize 옵션 및 parquet 파일 형식을 활용한 최종 데이터 전처리
그럼 파이썬으로 빅데이터 분석은 영원히 할 수 없는 걸까요? 그렇지 않습니다. pandas 라이브러리의 read_csv 함수의 chunksize 옵션을 활용하여 빅데이터 분석에 용이한 parquet 파일로 변환하여 분석하면 해결할 수 있습니다.
해결 방법은 빅데이터 분석을 위한 데이터 전처리1 및 빅데이터 분석을 위한 데이터 전처리2 를 참고하시면 됩니다.
CSV 파일을 parquet 파일로 변환하는 최종 파이썬 코드는 아래와 같습니다.
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
chunksize = 200000
csvStream = pd.read_csv("D:/big_data/big_data.csv", sep = ',', encoding = 'EUC-KR', error_bad_lines = False, chunksize = chunksize, low_memory=False)
chunk = next(iter(csvStream))
# 처음 100000개의 데이터를 활용하여 CSV 파일의 스키마 추정
parquetSchema = pa.Table.from_pandas(df = chunk).schema
# 만약, 데이터의 스키마를 미리 알고 있다면, 미리 지정해 주는 것이 좋습니다.
# parquetSchema = pa.schema([
# ('변수명1', 형식1), -> 예시: ('var1', pa.int64()),
# ('변수명2', 형식2), -> 예시: ('var2', pa.string()),
# ...
# ('변수명n', 형식n)
# ])
# CSV 파일을 청크 단위로 가져오기
chunksize = 50000
csvStream = pd.read_csv("D:/big_data/big_data.csv", sep = ',', encoding = 'EUC-KR', error_bad_lines = False, chunksize = chunksize, low_memory=False)
for i, chunk in enumerate(csvStream):
print("Chunk", i)
if i == 0:
# 데이터를 쓰기 위한 파케이(parquet) 파일 열기
parquetWriter = pq.ParquetWriter(where = "D:/big_data/big_data.parquet", schema = parquetSchema, compression = 'snappy')
# 청크로 가져온 csv 파일을 파케이(parquet) 파일로 쓰기
table = pa.Table.from_pandas(chunk, schema = parquetSchema)
parquetWriter.write_table(table)
# 파케이(parquet) 파일 닫기
parquetWriter.close()
최종 D드라이브에 csv 파일명과 동일한 파일명의 parquet 파일이 생성되었습니다. 파일 용량이 88%나 줄어들었음을 확인할 수 있습니다. 이렇게 생성된 parquet 파일을 활용하면 메모리를 효율적으로 관리하면서도 데이터 분석 속도가 매우 빨라졌다는 것을 확인하실 수 있을 것입니다.
감사합니다!!