티스토리 뷰

#11 판다스 chapter 11. 누락값 처리하기

 

누락값 처리하기

누락값이란?

- 누락값과 누락값 확인하기

누락값(NaN)은 Nan,NAN,nan 과 같은 방법으로 표기할 수 있다. 실습을 진행하며 누락값이 무엇인지 알아보자.

 

  • 누락값 확인하기

1) 먼저 누락값을 사용하기 위해 numpy에서 누락값을 불러온다.

 

from numpy import NaN,NAN,nan

 

2) 누락값은 0, ' ' 과 같은 값과는 다른 개념이다. 누락값은 말 그대로 데이터 자체가 없다는 것을 의미한다. 그래서 '같다'라는 개념도 없다. 다음은 누락값과 True, False, 0, '' 을 비교한 결과이다.

 

print(NaN == True)

False

print(NaN == False)

False

print(NaN == 0)

False

print (NaN == '')

False

 

3) 과정 2에서도 언급했듯이 누락값은 값 자체가 없기 때문에 자기 자신과 비교해도 True가 아닌 False가 출력된다.

 

print(NaN == NaN)

False

print(NaN == nan)

False

print(NaN == NAN)

False

print(nan == NAN)

False

 

4) 그렇다면 누락값은 어떻게 확인할까? 다행히 판다스에는 누락값을 확인하는 메서드인 isnull이 있다. 아래는 isnull 메서드로 누락값을 검사한것이다.

 

import pandas as pd

print (pd.isnull(NaN))

True

print(pd.isnull(nan))

True

print(pd.isnull(NAN))

True

 

5) 반대의 경우도 검사할 수 있다. 아래는 notnull 메서드로 누락값이 아닌 경우를 검사한 예이다.

 

print(pd.notnull(NaN))

False

print(pd.notnull(nan))

False

print(pd.notnull(NAN))

False

 

- 누락값이 생기는 이유

  • 누락값이 생기는 이유 알아보기

1) 누락값이 있는 데이터 집합을 연결할 때 누락값이 생기는 경우

 

이번에 사용할 데이터 집합은 누락값이 포함되어 있다. 누락값이 포함되어 있는 데이터 집합을 연결하면 어떻게 될까? 누락값이 포함되어 있는 데이터 집합을 연결하면 더 많은 누락값이 생긴다.

 

visited = pd.read_csv('../data/survey_visited.csv')
survey = pd.read_csv('../data/survey_survey.csv')

print(visited)

   ident   site       dated
0    619   DR-1  1927-02-08
1    622   DR-1  1927-02-10
2    734   DR-3  1939-01-07
3    735   DR-3  1930-01-12
4    751   DR-3  1930-02-26
5    752   DR-3         NaN
6    837  MSK-4  1932-01-14
7    844   DR-1  1932-03-22

print(survey)

    taken person quant  reading
0     619   dyer   rad     9.82
1     619   dyer   sal     0.13
2     622   dyer   rad     7.80
3     622   dyer   sal     0.09
4     734     pb   rad     8.41
5     734   lake   sal     0.05
6     734     pb  temp   -21.50
7     735     pb   rad     7.22
8     735    NaN   sal     0.06
9     735    NaN  temp   -26.00
10    751     pb   rad     4.35
11    751     pb  temp   -18.50
12    751   lake   sal     0.10
13    752   lake   rad     2.19
14    752   lake   sal     0.09
15    752   lake  temp   -16.00
16    752    roe   sal    41.60
17    837   lake   rad     1.46
18    837   lake   sal     0.21
19    837    roe   sal    22.50
20    844    roe   rad    11.25

 

2) 과정 1에서 구한 데이터 집합을 연결해 보자. 그러면 누락값이 많이 생겨난 것을 볼 수 있다.

 

vs = visited.merge(survey, left_on='ident', right_on='taken')
print(vs)

ident   site       dated  taken person quant  reading
0     619   DR-1  1927-02-08    619   dyer   rad     9.82
1     619   DR-1  1927-02-08    619   dyer   sal     0.13
2     622   DR-1  1927-02-10    622   dyer   rad     7.80
3     622   DR-1  1927-02-10    622   dyer   sal     0.09
4     734   DR-3  1939-01-07    734     pb   rad     8.41
5     734   DR-3  1939-01-07    734   lake   sal     0.05
6     734   DR-3  1939-01-07    734     pb  temp   -21.50
7     735   DR-3  1930-01-12    735     pb   rad     7.22
8     735   DR-3  1930-01-12    735    NaN   sal     0.06
9     735   DR-3  1930-01-12    735    NaN  temp   -26.00
10    751   DR-3  1930-02-26    751     pb   rad     4.35
11    751   DR-3  1930-02-26    751     pb  temp   -18.50
12    751   DR-3  1930-02-26    751   lake   sal     0.10
13    752   DR-3         NaN    752   lake   rad     2.19
14    752   DR-3         NaN    752   lake   sal     0.09
15    752   DR-3         NaN    752   lake  temp   -16.00
16    752   DR-3         NaN    752    roe   sal    41.60
17    837  MSK-4  1932-01-14    837   lake   rad     1.46
18    837  MSK-4  1932-01-14    837   lake   sal     0.21
19    837  MSK-4  1932-01-14    837    roe   sal    22.50
20    844   DR-1  1932-03-22    844    roe   rad    11.25

 

3) 데이터를 입력할 때 누락값이 생기는 경우

 

누락값은 데이터를 잘못 입력하여 생길 수도 있다. 다음은 시리즈를 생성할 때 데이터프레임에 없는 열과 행 데이터를 입력하여 누락값이 생긴 것이다. scientists 데이터프레임을 확인하면 missing이라는 열과 함께 행 데이터에 누락값이 추가된 것을 확인할 수 있다.

 

num_legs = pd.Series({'goat': 4, 'amoeba': nan})
print(num_legs)
print(type(num_legs))

num_legs = pd.Series({'goat': 4, 'amoeba': nan})
print(num_legs)
print(type(num_legs))

scientists = pd.DataFrame({
    'Name' : ['Rosaline Franklin', 'William Gosset'],
    'Occupation' : ['Chemist', 'Statistician'],
    'Born' : ['1920-07-25', '1876-06-13'],
    'Died' : ['1958-04-16', '1937-10-16'],
    'missing' : [NaN, nan]})

print(scientists)
print(type(scientists))

 Name    Occupation        Born        Died  missing
0  Rosaline Franklin       Chemist  1920-07-25  1958-04-16      NaN
1     William Gosset  Statistician  1876-06-13  1937-10-16      NaN
<class 'pandas.core.frame.DataFrame'>

 

4) 범위를 지정하여 데이터를 추출할 때 누락값이 생기는 경우

 

데이터프레임에 존재하지 않는 데이터를 추출하면 누락값이 생긴다. 이번엔 갭마인더 집합을 불러와서 실습해보자.

 

gapminder = pd.read_csv('C../data/gapminder.tsv', sep='\t')

 

5) 다음은 gapminder 데이터프레임을 연도별로 그룹화한 다음 lifeExp 열의 평균을 구한 것이다.

 

life_exp = gapminder.groupby(['year'])['lifeExp'].mean()
print(life_exp)

year
1952    49.057620
1957    51.507401
1962    53.609249
1967    55.678290
1972    57.647386
1977    59.570157
1982    61.533197
1987    63.212613
1992    64.160338
1997    65.014676
2002    65.694923
2007    67.007423
Name: lifeExp, dtype: float64

 

6) 다음은 range 메서드를 이용하여 life_Exp 열에서 2000~2009년의 데이터를 추출한 것이다. 그런데 이렇게 데이터를 추출하면 처음부터 life_Exp 열에 없었던 연도가 포함되기 때문에 누락값이 많이 발생한다.

 

print(life_exp.loc[range(2000, 2010), ])

KeyError: "Passing list-likes to .loc or [] with any missing labels is no longer supported. 
The following labels were missing: Int64Index([2000, 2001, 2003, 2004, 2005, 2006, 2008, 2009], 
dtype='int64', name='year'). See https://pandas.pydata.org/pandas-docs/stable/user_guide/
indexing.html#deprecate-loc-reindex-listlike"

 

7) 앞에서 발생한 문제를 해결하기 위해서는 불린 추출을 이용하여 데이터를 추출하면 된다.

 

y2000 = life_exp[life_exp.index > 2000]
print(y2000)

year
2002    65.694923
2007    67.007423
Name: lifeExp, dtype: float64

 

누락값의 개수

  • 누락값의 개수 구하기

1) 다음과 같이 입력하여 데이터를 불러오자.

 

ebola = pd.read_csv('../data/country_timeseries.csv')

 

2) 먼저 count 메서드로 누락값이 아닌 값의 개수를 구해보자.

 

print(ebola.count())

Date                   122
Day                    122
Cases_Guinea            93
Cases_Liberia           83
Cases_SierraLeone       87
Cases_Nigeria           38
Cases_Senegal           25
Cases_UnitedStates      18
Cases_Spain             16
Cases_Mali              12
Deaths_Guinea           92
Deaths_Liberia          81
Deaths_SierraLeone      87
Deaths_Nigeria          38
Deaths_Senegal          22
Deaths_UnitedStates     18
Deaths_Spain            16
Deaths_Mali             12
dtype: int64

 

3) 과정 2의 결과만 잘 활용해도 누락값의 개수를 쉽게 구할 수 있다. shape[0]에 전체 행의 데이터 개수가 저장되어 있다는 점을 이용하여 shape[0] 에서 누락값이 아닌 값의 개수를 빼면 누락값의 개수를 구할 수 있다.

 

num_rows = ebola.shape[0]
num_missing = num_rows - ebola.count()
print(num_missing)

Date                     0
Day                      0
Cases_Guinea            29
Cases_Liberia           39
Cases_SierraLeone       35
Cases_Nigeria           84
Cases_Senegal           97
Cases_UnitedStates     104
Cases_Spain            106
Cases_Mali             110
Deaths_Guinea           30
Deaths_Liberia          41
Deaths_SierraLeone      35
Deaths_Nigeria          84
Deaths_Senegal         100
Deaths_UnitedStates    104
Deaths_Spain           106
Deaths_Mali            110
dtype: int64

 

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

 

import numpy as np

print(np.count_nonzero(ebola.isnull()))

1214

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

29

 

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

 

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

NaN      29
86.0      3
112.0     2
390.0     2
495.0     2
Name: Cases_Guinea, dtype: int64

 

누락값 처리하기

누락값은 누락값을 임의의 값으로 변경하거나 데이터프레임에 이미 있는 값으로 대신 채우는 방법 등으로 처리할 수 있다.

  • 누락값 처리하기 -- 변경, 삭제

1) 누락값 변경하기

 

데이터프레임에 포함된 fillna 메서드에 0 을 대입하면 누락값을 0으로 변경한다. fillna메서드는 처리해야 하는 데이터프레임의 크기가 매우 크고 메모리를 효율적으로 사용해야 하는 경우에 자주 사용하는 메서드이다.

 

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

         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

 

2) fillna 메서드의 method 인잣값을 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

 

3) method 인잣값을 bfill로 지정하면 누락값이 나타난 이후의 첫 번째 값으로 앞쪽의 누락값이 모두 변경된다. 과정2의 반대 방향으로 처리한다고 생각하면 된다.

 

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

 

4) 과정 2, 3 에서는 데이터프레임의 값을 그대로 사용하여 누락값을 처리했다. 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

 

5) 누락값 삭제하기

 

누락값이 필요 없을 경우에는 누락값을 삭제해도 된다. 하지만 누락값을 무작정 삭제하면 데이터가 너무 편향되거나 데이터의 개수가 너무 적어질 수도 있다. 먼저 ebola의 데이터 구조를 확인해보자.

 

print(ebola.shape)

(122, 18)

 

6) 누락값을 삭제하기 위해 dropna 메서드를 사용하자. 누락값이 포함된 행들이 모두 삭제되기 때문에 많은 데이터가 삭제되었다.

 

ebola_dropna = ebola.dropna()
print(ebola_dropna.shape)

(1, 18)

print(ebola_dropna)

          Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone  \
19  11/18/2014  241        2047.0         7082.0             6190.0   

    Cases_Nigeria  Cases_Senegal  Cases_UnitedStates  Cases_Spain  Cases_Mali  \
19           20.0            1.0                 4.0          1.0         6.0   

    Deaths_Guinea  Deaths_Liberia  Deaths_SierraLeone  Deaths_Nigeria  \
19         1214.0          2963.0              1267.0             8.0   

    Deaths_Senegal  Deaths_UnitedStates  Deaths_Spain  Deaths_Mali  
19             0.0                  1.0           0.0          6.0 

 

누락값이 포함된 데이터 계산하기

만약 누락값이 포함된 데이터를 계산하려면 어떻게 해야할까? 다음은 여러 지역에서 발생한 ebola 발병 수를 구하는 실습이다.

 

  • 누락값이 포함된 데이터 계산하기

1) Guinea,Liberia,SierraLeone 열에는 누락값들이 존재한다. 만약 누락값이 존재하는 Guinea,Liberia,SierraLeone 열을 가지고 ebola 발병 수의 합을 계산하면 어떻게 될까? 다음은 Cases_Guinea, Cases_Liberia, Cases_SierraLeone 열을 더하여 Cases_multiple 열을 새로 만든 것이다.

 

ebola['Cases_multiple'] = ebola['Cases_Guinea'] + ebola['Cases_Liberia'] + 
ebola['Cases_SierraLeone']

 

2) 앞서 계산한 Cases_multiple 열을 포함하여 ebola_subset 이라는 데이터프레임을 새로 만들어 어떤 값이 존재하는지 확인해보자. 누락값이 하나라도 있는 행은 계산결과 NaN이 되었음을 알 수 있다. 즉, 계산 결과 누락값이 더 많이 생겼다.

 

ebola_subset = ebola.loc[:, ['Cases_Guinea', 'Cases_Liberia', 'Cases_SierraLeone', 'Cases_multiple' ]]
print(ebola_subset.head(n=10))

 Cases_Guinea  Cases_Liberia  Cases_SierraLeone  Cases_multiple
0        2776.0            NaN            10030.0             NaN
1        2775.0            NaN             9780.0             NaN
2        2769.0         8166.0             9722.0         20657.0
3           NaN         8157.0                NaN             NaN
4        2730.0         8115.0             9633.0         20478.0
5        2706.0         8018.0             9446.0         20170.0
6        2695.0            NaN             9409.0             NaN
7        2630.0         7977.0             9203.0         19810.0
8        2597.0            NaN             9004.0             NaN
9        2571.0         7862.0             8939.0         19372.0

 

3) Cases_multiple 열을 sum메서드를 사용해 더하면 세 지역의 ebola 발병 수의 합을 구할 수 있다. 이때 sum 메서드를 그냥 사용하면 누락값을 포함해 계산한다. 따라서 결괏값도 누락값이 된다. 누락값을 무시한 채 계산하려면 skipna 인잣값을 True로 설정하면 된다.

 

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

84729.0

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

nan

 

데이터 분석 분야는 누락값을 처리하는 능력이 매우 중요하다. 데이터를 통해 의사 결정이나 추론을 하려면 반드시 필요한 능력이다.
누락값은 언제 어디서든 생길 수 있기 때문에 누락값을 처리하는 방법을 반드시 숙지하자.

 

 

출처 : 데이터 분석을 위한 판다스 입문

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함