본문 바로가기
데이터 분석/데이터 전처리

[Pandas] 15. 결측치(Missing Value) 처리하기

by 부자 꽁냥이 2020. 12. 2.

안녕하세요~ 꽁냥이에요.

 

대부분의 데이터는 꽉 채워져 있는 것이 아닌 빈 데이터가 포함되어 있지요. 이러한 빈 데이터를 결측치라고 합니다. 데이터 분석자는 이러한 결측치를 제거하거나 대체하는 등 적절한 처리를 해야 합니다.

 

따라서 이번 포스팅에서는 결측치(또는 결측값)를 처리하는 방법에 대해서 소개하려고 합니다. 여기서 다루는 결측치는 빈 문자열, None, NaN 총 3가지이며 이번 포스팅에서 다루는 내용은 다음과 같습니다(None과 NaN에 대한 설명은 여기를 참고하세요).

 

1. 결측치 확인

2. 결측치 대체

3. 결측치 제거


   1. 결측치 확인

먼저 이번 포스팅에서 사용할 데이터를 만들어봅시다.

 

import pandas as pd
import numpy as np

data = {
    'Fruit' : ['Apple',None,'Banana','',np.nan,'Strawberry','Banana','Banana','Apple'],
    'Age' : [np.nan, 14, 13, 22, 14, np.nan, 31, np.nan,None],
    'Height' : [187,181,155,165,177,171,170,179,164]
}
df = pd.DataFrame(data)

 

 

결측값을 확인하는 방법에는 info와 isna를 이용하는 방법이 있습니다. 

 

df.info()

 

line 1

info는 데이터의 칼럼명, 결측치를 제외한 데이터 개수, 데이터 타입을 알려줍니다. 

 

 

위 결과는 df.info()를 실행한 결과입니다. 이를 통하여 결측치의 유무를 확인해보겠습니다. 먼저 RangeIndex 옆에 9 entries에서 숫자 9는 전체 데이터를 말합니다. 그리고 아래쪽에 칼럼 이름 옆에 숫자 7, 5, 9는 결측값이 아닌 데이터의 개수입니다. 따라서 전체 데이터 개수 9에서 각각의 숫자를 빼주면 Fruit 열에는 2개, Age 열에는 4개, Height 열에는 0개의 결측값이 있다는 것을 확인할 수 있습니다. 이를 통해서 None과 NaN을 똑같이 취급한다는 것을 알 수 있습니다.

 

info를 이용한 방법은 결측치의 존재 유무뿐만 아니라 결측치의 개수까지 확인할 수 있다는 장점이 있지만 빈 문자열과 같은 결측값은 잡아내지 못합니다.

 

이번에는 isna를 사용해보겠습니다.

 

df.isna().any()

 

line 1

isna는 단독으로 사용하지 않고 any를 같이 사용합니다. 여기서 any함수는 해당 조건에 맞는 데이터가 하나라도 있으면 True를 모든 데이터가 해당조건에 맞지 않으면 False를 리턴하는 함수입니다. 위 코드를 실행해보세요.

 

 

단순히 결측치의 개수가 아닌 존재 유무만 확인하고 싶다면 isna와 any를 사용하면 됩니다. 하지만 빈 문자열과 같은 결측값은 역시 잡아내지 못합니다.

 

이번에는 빈 문자열의 존재 유무를 확인해보겠습니다.

 

def is_emptystring(x):
    return x.eq('').any()

df.apply(lambda x:is_emptystring(x))

 

line 1~2

빈 문자열을 확인하는 함수는 직접 만들어줘야 합니다.

 

line 4

apply를 이용하여 위에서 만들어둔 함수를 적용시킵니다.

 

 

위 코드를 실행시키면 Fruit에 빈 문자열이 있음을 확인할 수 있습니다.

반응형

   2. 결측치 대체

fillna를 이용하면 결측치를 대체할 수 있습니다. 꽁냥이는 Fruit의 결측치는 최빈값으로 Age의 결측치는 평균으로 대체해보겠습니다.

 

df.fillna({'Fruit':df['Fruit'].mode()[0],'Age':int(df['Age'].mean())},inplace=True)

 

line 1

칼럼명을 Key로 넣어줄 값을 Value로 하는 딕셔너리를 fillna의 첫 번째 인자에 넣어주고요. 데이터 원본의 바로 반영하기 위하여 inplace를 True로 했습니다.

 

 

위 그림에서 보듯이 결측치가 잘 채워진 것을 확인할 수 있습니다.

 

만약 모든 결측치를 같은 값으로 넣고자 한다면 딕셔너리를 사용하지 않고 다음과 같이 사용하면 됩니다.

 

df.fillna( 넣어줄 값 )

 

이 방법은 데이터의 타입이 모두 같은 경우에 생각해볼 수 있는 방법입니다.

 

이번에는 Fruit의 빈 문자열을 최빈값으로 대체해보겠습니다.

 

df = df.replace(' ','').replace('',df['Fruit'].mode()[0])

 

line 1

첫 번째 replace는 공백 문자를 모두 빈 문자열로 만들어주기 위해 사용했으며 두 번째 replace가 빈 문자열을 최빈값으로 대체해줍니다. 위 코드를 실행해서 결과를 확인하면 아래와 같이 최빈값 'Banana'가 잘 채워진 것을 확인할 수 있습니다.

 

 


   3. 결측치 제거

결측치를 제거하는 방법에는 행단위로 제거하는 방법과 열단위로 제거하는 방법이 있습니다. 먼저 위 데이터를 다시 만들겠습니다.

 

data = {
    'Fruit' : ['Apple',None,'Banana','',np.nan,'Strawberry','Banana','Banana','Apple'],
    'Age' : [np.nan, 14, 13, 22, 14, np.nan, 31, np.nan,None],
    'Height' : [187,181,155,165,177,171,170,179,164]
}
df = pd.DataFrame(data)

 

1. 결측치 행 단위로 제거

 

먼저 칼럼에 관계없이 모든 결측값을 제거하고 싶다면 아래와 같이 해주면 됩니다.

 

df.dropna()

 

 

이번에는 Fruit의 결측값이 있는 행만 제거해보겠습니다.

 

df.dropna(subset=['Fruit'])

 

line 1

dropna의 subset인자에 결측값을 확인할 칼럼명을 리스트로 담아서 넣어주세요.

 

 

위 그림과 같이 Fruit의 결측값에 해당하는 행만 제거했습니다.

 

다음으로 빈 문자열에 해당하는 행을 제거해보겠습니다. query를 이용합니다.

 

df.query('Fruit != ""')

 

 

2. 결측치 열 단위로 제거

 

이번에는 결측값이 있는 모든 칼럼을 삭제해보겠습니다.

 

df.dropna(axis=1)

 

line 1

dropna의 axis인자에 1을 넣어주면 됩니다.

 

 

 

다음으로 첫 번째 행에 결측치를 포함하고 있는 칼럼을 삭제해보겠습니다. 첫 번째 행에는 Age 칼럼만이 결측치를 포함하고 있으므로 Age 칼럼이 삭제됩니다.

 

df.dropna(axis=1,subset=[0])

 

line 1

dropna의 subset인자에 결측치를 확인하고자 할 행 인덱스를 리스트로 넣어주면 됩니다.

 

 

이번에는 빈 문자열을 포함하는 칼럼을 삭제해보겠습니다. 이때에는 dropna를 사용할 수 없고 아래와 같이 해주어야합니다(다른 방법도 있을 수 있습니다).

 

def is_emptystring(x):
    return x.eq('').any()

res = df.apply(lambda x:is_emptystring(x))

## 빈문자열을 포함하지 않는 칼럼이름을 리스트에 담는다.
valid_column = [i for v, i in zip(res.values, res.index) if v == False] 
df[valid_column]

 

line 1~4

각 칼럼이 빈문자열을 포함하고 있는지 아닌지 확인해주는 함수를 만들고 이를 apply를 이용해 적용시켜줍니다. 

 

line 5

빈문자열을 포함하지 않는 칼럼 이름을 리스트에 담아줍니다.

 

위 코드를 실행하면 아래와 같이 빈 문자열이 포함된 Fruit 칼럼이 삭제된 것을 알 수 있습니다.

 


이번 포스팅에서는 결측값을 처리하는 방법에 대해서 알아보았습니다. 결측치는 데이터 분석을 하면 자주 만나게 되므로 오늘 배운 내용을 숙지하신다면 써먹을 곳이 많이 있을 거예요.

 

지금까지 꽁냥이의 글 읽어주셔서 감사합니다. 안녕히 계세요.


 

댓글


맨 위로