공부한 것 꼭꼭 씹어먹기

파이썬 판다스 na_filter: NA(North America)는 null이 아니다 본문

소소한 개발 지식

파이썬 판다스 na_filter: NA(North America)는 null이 아니다

젤라솜 2022. 10. 18. 10:37
반응형

파이썬 판다스로 csv파일 읽기

최근에 갑자기 파이썬을 쓸 일이 생겼습니다. pandas라는 파이썬 라이브러리도 함께 말이죠. Python용 pandas 라이브러리는 데이터 형식 지정, 탐색적 데이터 분석 수행, 모델링 및 기계 학습에 사용할 데이터 준비에 매우 유용합니다. 그래서 빅데이터 분석 작업에 가장 많이 쓰이는 라이브러리가 pandas입니다. 빅데이터의 소스 데이터로 많이 쓰이는 csv파일은 가장 일반적인 파일 형식 중 하나로 엑셀 스프레드 시트와 같은데요. 쉼표로 구분된 값을 저장하는 csv파일은 데이터 유형과 같은 것에 대해 걱정할 필요 없이 기본적으로 .csv 파일로 작업할 수 있도록 합니다. Python에서 이러한 csv 파일을 사용하기 위해 pandas 라이브러리는 pd.read_csv()라는 함수를 제공하는데요. csv 파일을 데이터 프레임(dataframe:파이썬의 자료구조)으로 구문 분석할 뿐만 아니라 구문 분석 방법 을 보다 세부적으로 제어할 수 있는 매우 유용한 기능을 제공합니다. 판다스로 이것저것 해보다가 na_filter라는 인자(argument)에 관심이 가게 되었습니다. default는 true인데 판다스가 결측치(null)를 어떻게 분석할지를 결정하는 인자입니다. pd.read_csv()로 csv 파일을 호출할 때 na_filter 인수는 파일에서 값을 찾고 빈 셀 또는 "NA"("N/A", "NA", " NaN” 등. 자세한 내용은 설명서 참조). 데이터 프레임의 해당 값에 대해 NaN 값을 배치합니다. (NaN은 파이썬에서 말하는 결측치) 즉, na_filter = True일때  "NA", "N/A", "-", "#N/A"와 같은 값들은 NaN으로 취급하게 하는 것이죠. 매우 유용한 설정입니다!

 

하지만 왜 na_filter = False로도 설정할 수 있는 자유를 준 것일까요?

어떤 경우에, 왜 na_filter = False로 쓸까요?

 

제가 지금 다루고 있는 데이터에는 region 컬럼에 "NA"라는 값이 들어가 있습니다. 즉, 지역이 North America 인 경우가 있는데요. 이때 na_filter가 True라면 North America는 NaN으로 취급되고 맙니다.  이럴때 na_filter를 False로 해놓으면 North America의 약자인 NA는 결측값이 아닌 문자열 "NA"로 인식되는 것입니다. 그리고 또 다른 이유로는, 만약 이 파일에 NA값이 없고 파일이 매우 크다면 na_filter를 False로 해놓음으로써 파싱 속도를 높일 수 있다고 합니다. 즉, NA값이 없는 파일을 불필요하게 필터링 하지 않게 해서 파일을 더 빨리 읽을 수 있게 하는 것이죠. 그런데 NA 값이 파일에 있고 na_filter = False로 했을 경우 dataframe에 공백으로 나오는 경우가 있을 수 있습니다. 그렇다고 그것이 null값으로 표시되는 것도 아니구요!

 

import pandas as pd

# csv파일을 import하고 na_filter는 false로 줍니다
df = pd.read_csv("file.csv", na_filter=False)

# 데이터프레임(df)의 첫 두줄만 보여줍니다
df.head(2)
>>> [col1, col2, col3
     1.5  ,     , foo
         ,  bar,    ]
         
# 공백이 많이 있는 파일 같네요! 결측값의 개수를 세어보겠습니다
df.isnull().sum()
>>> col1   0
    col2   0
    col3   0

 

공백은 당연히 결측값에 해당하는 데도 df.isnull().sum()하면 결측값이 없다고 나오네요. 그래서 검색하다가 이런 방법을 써봤습니다. df.col1.replace('', np.nan) 넘파이를 이용해 데이터프레임의 공백을 NaN으로 교체해주는 것입니다. 그런데 이렇게 했더니 col1의 dtype이 object로 나옵니다.  1.5라는 값이 해당 컬럼에 있으면 float을 출력해야 하는데 말이죠.

df.col1.dtype
>>> col1     object

이유는 잘 모르겠지만 판다스는 이 컬럼을 객체로 취급하고 있습니다. 그래서 또 인위적으로 데이터 타입을 바꿔봤습니다. df.col1.astype(float, inplace=True) 하지만 공백에 대해 이것은 적용이 되지 않습니다. 게다가 이걸 언제 일일히 하고 있나요. 그리고 뭔가 원본 데이터에 인위적인 손을 데는것 같아서 찝찝한 찰나였습니다.

다시 한번, 저의 요구사항을 정리해봤습니다.

1. North America의 약자인 "NA"는 NaN으로 처리되지 않아야 한다.

2. 공백, "#NA", "N/A" 등은 NaN으로 처리되어야 한다.

 

 

read_csv()함수의 na_filter 활용하기

지금까지 na_filter를 통해 발견한 딜레마는 이것입니다. na_filter = True일 경우 North America는 NaN으로 인식되지만 다른 결측값들은 제대로 NaN으로 인식이 된다. na_filter = False일 경우 North America는 "NA"라는 문자열로 인식되지만 다른 결측값을 걸러낼 수 없다. 검색끝에 read_csv()함수의 인자들을 잘 조합해서 해결했습니다.

df = pd.read_csv("file.csv"
                , na_filter = True
                , keep_default_na = False
                , na_values=['', '#NA', 'null', '#N/A'])

na_filter = True 입니다. 즉, 결측값을 걸러내겠다고 하는 것이죠. 여기까지만 하면 North America는 결측값으로 취급됩니다. 하지만 keep_default_na = False로 설정함으로써 default 결측값을 안쓰겠다고 하는 것입니다. 그리고 사용자가 na_values를 지정해주면 됩니다. 이때, na_values에 'NA'를 포함하지 않으면 'NA'는 결측값으로 여겨지지 않아서 문자열 그대로 잘 표출되고 나머지 결측값들(공백, '#NA', 'null', '#N/A'등)은 제대로 결측값으로 취급됩니다. 짧게 얘기하자면, 디폴트로 설정되어 있는 결측값 중 NA는 빼고 쓰겠다 라는 말인 것이죠. 이렇게하면 NA는 비로소 깔끔하게 North America가 됩니다!

 

 

 

 
 
 
 
반응형
Comments