본문 바로가기

언어/Python

[Python] Python(파이썬) 빠진 데이터를 처리하는 방법

Pandas에서의 빠진 데이터 표현

with open("data/nan_sample.csv", "rt", encoding="utf8") as f:
    print(f.read())

Pandas에서는 numpy의 nan 객체를 활용한다. (numpy.nan -> Not a Number)

NaN 데이터는 Pandas 연산에서 대부분 제외된다.

 

위의 예제 코드를 보면 '벤' 항목에서는 뒤의 데이터가 빠져있는 것을 확인할 수 있다. 이렇게 빠진 데이터를 표현하는 방법을 다뤄본다.

 

빠진 데이터를 0으로 채우는 방법(fillna)

import pandas as pd

df = pd.read_csv("data/nan_sample.csv", encoding="utf8")
print(df.shape)
df.head()

Pandas를 사용하여 csv 파일을 읽어보면 좋아요 열에서 빠진 데이터 부분이 NaN(Not a Number) 처리되어있다.

 

case1 = df['좋아요'].sum() / 5 # 평균을 직접 계산
case2 = df['좋아요'].mean() # 평균을 함수를 사용하여 계산
print(case1)
print(case2)

그런데 위의 예제 코드처럼 두 가지 방법으로 '좋아요' 항목의 평균을 계산해보면 다른 값이 나온다. 그 이유는 NaN값은 mean 함수의 범위에서 자동으로 제외되기 때문이다. 따라서 mean 함수는 NaN이 포함된 행을 제외하고 나머지 4개의 행에 대해서만 평균을 계산한다. (df['좋아요'].sum() / 4)

 

df['좋아요'].fillna(0)

평균을 계산할 때 NaN의 값을 '0'으로 채우는 방법은 무엇일까? 우선 데이터에 따라 다르게 처리가 가능하다. dataframe의 fillna 함수를 사용하면 NaN에 대해 어떤 값을 채울 것인지 결정할 수 있다. 예제 코드를 실행해보면 NaN이 아닌 0의 값으로 채워진 것을 확인할 수 있다.

 

case1 = df['좋아요'].sum() / 5
case2 = df['좋아요'].fillna(0).mean()
print(case1)
print(case2)

fillna 함수를 사용하여 NaN을 0으로 채우고 mean 함수를 사용하여 평균을 구해보면 직접 계산한 값과 똑같은 결과를 확인할 수 있다.

 

value = df['좋아요'].mean()
df['좋아요'] = df['좋아요'].fillna(value)
df

위의 예제 코드는 dataframe의 평균 값을 구한 후에 fillna 함수를 사용하여 NaN 값을 평균 값으로 채워준다. 이와 같이 다양한 응용이 가능하다. 그리고 어떤 값을 NaN에 채울 지는 파이썬 코드를 통해서 결정할 수 있고 Pandas뿐만 아니라 별도의 서버 API 또는 분석 코드를 사용할 수도 있다.

빠진 데이터를 찾아주는 방법(missingno)

처리하고자 하는 데이터의 개수가 적을 때에는 어떤 데이터가 NaN인지 한 눈에 파악하기 쉽다. 하지만 데이터가 많을 경우에는 어떤 데이터 혹은 어떤 시리즈에 NaN이 얼마나 많이 존재하는지 파악하기 어렵다. missingno는 이러한 부분들을 도와주는 별도의 써드파티 라이브러리이다.

 

https://github.com/ResidentMario/missingno

missingno 라이브러리를 사용하면 NaN를 파악하기 위한 시각화 자료를 제공해주며 검정색 데이터는 실제 값이 있음을 나타낸다. 흰색으로 표시되는 부분은 NaN이 있음을 의미한다. 위 라이브러리를 사용하기 위해서는 직접 설치가 필요하다.

설치 방법: pip install missingno

 

import numpy as np

df = pd.DataFrame(np.random.rand(100, 100)) # 100행 100열의 random array 생성
print(df.shape)
df.head()

numpy 라이브러리를 import한 후에 100행 100열의 random array를 생성하고 dataframe화 시킨다. 위의 예제 코드는 0이상 1 미만의 값들로 구성되어 있다.

 

cond = df > 0.3
df = df[cond]
print(df.shape)
df.head()

위의 dataframe에서 0.3 초과의 값만 남기고 df에 넣으면 0.3 이하의 값들은 NaN으로 채워진다.

 

import missingno as msno

%matplotlib inline
msno.matrix(df)

설치한 missingno를 import한 후에 시각화를 위해 matplotlib을 inline해준다. 위의 예제 코드를 수행해보면 NaN 현황을 확인할 수 있다. 위의 결과에서 하얀색 부분이 실제 NaN 값이다. 따라서 어떤 데이터에서 NaN값이 있는지 확인하려면 matrix를 사용하고 NaN를 어떻게 처리할지 고민해야 한다.

 

df.isnull()
# df.isna()

dataframe에서 isnull 함수 또는 isna 함수를 사용하면 NaN 부분이 True로 찍힌다.

 

df.notnull()
# df.notna()

위와 반대되는 함수는 notnull 함수 또는 notna 함수이다. NaN 부분이 False로 찍힌다.

빠진 데이터를 제거하는 방법(dropna)

df = pd.DataFrame(np.random.rand(100, 100)) # 100행 100열의 random array 생성

cond = df > 0.3
df = df[cond]

df.dropna('index', how='all')

한 번에 drop을 할 수 있는 함수는 dropna 함수이다. axis는 기준 축이고 0을 설정하면 missing values가 포함된 index들을 제거한다. 1로 설정하면 missing values가 포함된 columns를 제거한다. how 옵션에서 any를 사용할 경우 해당 행 또는 열에서 NaN 값이 하나라도 있다면 행 또는 열을 제거한다. all의 경우 행 또는 열이 NaN 값으로 모두 채워져 있을 때에만 제거한다.

결론

다양한 데이터를 처리하는 과정에서 계산 오류가 발생할 수 있으며 NaN 값이 할당된다. 이 값들은 총 개수에는 포함되지만 실제로 데이터를 처리하기 위한 계산에서는 제외되는 경우가 대부분이기 때문에 정확한 계산을 위해서는 NaN 포함 여부를 확인하고 에러를 줄여야 한다.