본문 바로가기

Pandas

데이타 결측치(누락값, 결측값) 처리하기 : fillna (ffill, bfill), dropna, isnull

반응형

데이타, 머신러닝 분석은 결측값 해결부터 시작합니다.


 

머신러닝의 모든 데이타는 숫자를 통해 행해지고 결측값 즉 NaN, NAN, nun과 같은 방법으로 표기되는 결측값을 처리해야 하는 문제가 있습니다.  모든 Machin Learning 프로그래머들은 해당 작업을 해야 하는 문제에 봉착합니다.

 

이를 처리하는 방법에 대해 알아보겠습니다.

 

1. 누락값 확인하기

누락값을 사용하기 위해 numpy에서 누락값을 불러옵니다.

from numpy import NAN, NaN, nan

 

누락값은 0, ' '와 같은 값과는 다른 개념이라는 것에 주의해야 합니다. 누락값은 말 그대로 데이터 자체가 없다는 것을 의미합니다. 아래값을 실행하면 모든 값은 False입니다. 즉 그 어떤것과도 같지 않습니다.

print(NaN == True)
print(NaN == False)
print(NaN == 0)
print(NaN =='')

 

아래값을 확인하면 역시 모든 결과는 False입니다. 값 자체가 없는것이죠.

print(NaN == NaN)
print(NaN == nan)
print(NaN == NAN)
print(nan == NAN)

 

누락값에 대한 확인은 pandas의 isnull 메서드를 통해 할 수 있습니다. 아래 값은 모두 True입니다. 즉 isnull은 해당값이 null인지 여부를 확인하여 null이면 True를 반환합니다.

import pandas as pd

print(pd.isnull(NaN))
print(pd.isnull(nan))
print(pd.isnull(NAN))

 

반대의 경우(누락값이 아닌 경우)도 검사할 수 있습니다. notnull 메소드를 통하면 됩니다. 아래값은 False, True, True입니다.

print(pd.notnull(NaN))
print(pd.notnull(42))
print(pd.notnull('missing'))

 

2. 누락값의 개수 구하기

누락값의 개수를 구하는 방법에 대해 알아보겠습니다.  실습 화일은 아래와 같습니다.

 

country_timeseries.csv
0.01MB

 

count 메소드로 누락값이 아닌 값의 개수를 구한 후 shape[0]에 전체 행의 데이터 개수가 저장되어 있다는 점을 이용하여 shape[0]에서 누락값이 아닌 값의 개수를 빼면 누락값의 개수를 구할 수 있습니다.

ebola = pd.read_csv(r'C:\Users\HANA\PycharmProjects\HANATOUR\Pandas\doit_pandas-master\data\country_timeseries.csv')
# print(ebola.count())
# print(ebola.shape)
num_rows = ebola.shape[0]
num_missing = num_rows = ebola.count()
print(num_missing)

 

count메서드를 사용해도 되지만 count_nonzero, isnull 메소드를 조합해도 누락값의 개수를 구할 수 있습니다.

import numpy as np
print(np.count_nonzero(ebola.isnull()))
print(np.count_nonzero(ebola['Cases_Guinea'].isnull()))

 

시리즈에 포함된 value_counts메서드는 지정한 열의 빈도를 구하는 메소드입니다. value_counts메서드를 사용해 Cases_Guinea열의 누락값 개수를 구혀려면 다음과 같이 입력합니다. 

print(ebola.Cases_Guinea.value_counts(dropna=False).head())

 

3. 누락값 처리하기

일단 원래값은 아래와 같다고 할 때

print(ebola.fillna(0).iloc[0:10, 0:5])

Name: Cases_Guinea, dtype: int64
         Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
0    1/5/2015  289        2776.0            0.0            10030.0
1    1/4/2015  288        2775.0            0.0             9780.0
2    1/3/2015  287        2769.0         8166.0             9722.0
3    1/2/2015  286           0.0         8157.0                0.0
4  12/31/2014  284        2730.0         8115.0             9633.0
5  12/28/2014  281        2706.0         8018.0             9446.0
6  12/27/2014  280        2695.0            0.0             9409.0
7  12/24/2014  277        2630.0         7977.0             9203.0
8  12/21/2014  273        2597.0            0.0             9004.0
9  12/20/2014  272        2571.0         7862.0             8939.0

 

 

fillna 메소드의 인자값을 ffill로 지정하는 경우 누락값이 나탄나기 전의 값으로 누락값이 변경됩니다. 예를 들어 6행의 누락값이 나타나기 전의 값인 5행의 값을 사용하여 누락값을 처리합니다. 하지만 0, 1행은 처음부터 누락값이기 때문에 누락값이 그대로 남아 있습니다.

print(ebola.fillna(method='ffill').iloc[0:10, 0:5])

         Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
0    1/5/2015  289        2776.0            NaN            10030.0
1    1/4/2015  288        2775.0            NaN             9780.0
2    1/3/2015  287        2769.0         8166.0             9722.0
3    1/2/2015  286        2769.0         8157.0             9722.0
4  12/31/2014  284        2730.0         8115.0             9633.0
5  12/28/2014  281        2706.0         8018.0             9446.0
6  12/27/2014  280        2695.0         8018.0             9409.0
7  12/24/2014  277        2630.0         7977.0             9203.0
8  12/21/2014  273        2597.0         7977.0             9004.0
9  12/20/2014  272        2571.0         7862.0             8939.0

 

bfill로 지정하면 누락값이 나타난 이후의 첫 번째 값으로 앞쪽의 누락값이 모두 변경됩니다. 하지만 이 방법도 마지막 값이 누락값인 경우에는 처리하지 못한다는 단점이 있습니다.

print(ebola.fillna(method='bfill').iloc[0:10, 0:5])

         Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
0    1/5/2015  289        2776.0         8166.0            10030.0
1    1/4/2015  288        2775.0         8166.0             9780.0
2    1/3/2015  287        2769.0         8166.0             9722.0
3    1/2/2015  286        2730.0         8157.0             9633.0
4  12/31/2014  284        2730.0         8115.0             9633.0
5  12/28/2014  281        2706.0         8018.0             9446.0
6  12/27/2014  280        2695.0         7977.0             9409.0
7  12/24/2014  277        2630.0         7977.0             9203.0
8  12/21/2014  273        2597.0         7862.0             9004.0
9  12/20/2014  272        2571.0         7862.0             8939.0

 

interpolate의 경우 누락값 양쪽에 있는 값을 이용하여 중간값을 구한 다음 누락값을 처리합니다. 이렇게 하면 데이터프레임이 일정한 간격을 유지하고 있는 것처럼 수정할 수 있습니다.

print(ebola.interpolate().iloc[0:10, 0:5])

         Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
0    1/5/2015  289        2776.0            NaN            10030.0
1    1/4/2015  288        2775.0            NaN             9780.0
2    1/3/2015  287        2769.0         8166.0             9722.0
3    1/2/2015  286        2749.5         8157.0             9677.5
4  12/31/2014  284        2730.0         8115.0             9633.0
5  12/28/2014  281        2706.0         8018.0             9446.0
6  12/27/2014  280        2695.0         7997.5             9409.0
7  12/24/2014  277        2630.0         7977.0             9203.0
8  12/21/2014  273        2597.0         7919.5             9004.0
9  12/20/2014  272        2571.0         7862.0             8939.0

 

dropna를 이용하여 누락값을 석제할 수 있습니다. 중요한 것은 무작정 삭제하면 데이터가 너무 편향되거나 데이터의 개수가 너무 적어질 수도 있습니다. 그래서 누락값을 삭제할 때는 분석하는 사람이 잘 판단해야 합니다. 

print(ebola.shape)
ebola_dropna = ebola.dropna()
print(ebola_dropna.shape)
print(ebola_dropna.iloc[0:10, 0:5])

 

3. 누락값 계산하기

결측값이 있을때 다른 열과 더하면 동일하게 결측값이 나오게 됩니다.  이때 skipna인자값을 True로 하면 결측값을 제외하고 계산이 됩니다.

print(ebola.Cases_Guinea.sum(skipna=True))
print(ebola.Cases_Guinea.sum(skipna=False))

84729.0
nan
반응형