티스토리 뷰
#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
데이터 분석 분야는 누락값을 처리하는 능력이 매우 중요하다. 데이터를 통해 의사 결정이나 추론을 하려면 반드시 필요한 능력이다.
누락값은 언제 어디서든 생길 수 있기 때문에 누락값을 처리하는 방법을 반드시 숙지하자.
출처 : 데이터 분석을 위한 판다스 입문
'판다스 입문' 카테고리의 다른 글
판다스 입문(판다스 자료형) (0) | 2021.03.21 |
---|---|
판다스 입문(깔끔한 데이터 만들기) (0) | 2021.03.21 |
판다스 입문( 데이터 연결하기) (0) | 2021.03.21 |
판다스 입문(데이터 프레임,시리즈로 그래프 그리기/seaborn 라이브러리로 그래프 스타일 설정하기) (0) | 2021.03.20 |
판다스 입문(그래프 그리기 - matplotlib, seaborn 라이브러리 사용하기) (0) | 2021.03.20 |