
DataFrame NaN 처리
NaN을 처리하기 용이하게끔 만들어주는 몇 가지 함수를 알아보자.
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
31
import numpy as np
import pandas as pd
np.random.seed(1) # 난수 사용을 위해 seed 설정
df = pd.DataFrame(np.random.randint(0, 10, (6, 4))) # 6x4 matrix 생성
df.columns = ['A', 'B', 'C', 'D'] # 컬럼명 설정
df.index = pd.date_range('20210801', periods=6) # 인덱스를 날짜로 주자.
display(df)
"""
A B C D
2021-08-01 5 8 9 5
2021-08-02 0 0 1 7
2021-08-03 6 9 2 4
2021-08-04 5 2 4 2
2021-08-05 4 7 7 9
2021-08-06 1 7 0 6
"""
# 새로운 column을 추가해보자
df['E'] = [7, np.nan, 4, np.nan, 2, np.nan] # 결치값이 들어가 있음.
display(df)
"""
A B C D E
2021-08-01 5 8 9 5 7
2021-08-02 0 0 1 7 NaN
2021-08-03 6 9 2 4 4
2021-08-04 5 2 4 2 NaN
2021-08-05 4 7 7 9 2
2021-08-06 1 7 0 6 NaN
"""
이렇게 결치값이 존재한다면 어떻게 해야하는가?
결치값 (NaN)을 가진 행 삭제
가장 간단한 방법은 결치값 (NaN)을 갖고 있는 행 삭제다.
물론 이게 경우에 따라선 좋은 방법일 수도 있지만, 보통은 그렇지 않다.
일단은 코드를 통해 알아보자!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# NaN은 missing values로 표기.
# 가장 간단한 방법은 NaN 값을 행을 삭제
# 상대적으로 데이터양이 많고 NaN이 비율적으로 적을때
# 이게 절대적인 기준은 없음. empirically observed.
# df.dropna를 이용해서 지울 수 있음.
df2 = df.dropna(how='any', inplace=False) # how가 any면 "nan값이 하나라도 등장하면 지워라" 이소리임.
# inplace=True 면 원본을 날림, False면 복사본
# 복사본일 경우 새로운 df에 assign해줘야함.
display(df2)
"""
A B C D E
2021-08-01 5 8 9 5 7
2021-08-03 6 9 2 4 4
2021-08-05 4 7 7 9 2
"""
df.dropna() 첫번째 인자로 들어오는 how=에 관해서는 대표적으로 all 또는 any를 받을 수 있다.
all일 경우:해당 행에 대한 칼럼값들이 전부
NaN일 경우 해당 행을 삭제한다.any일 경우:해당 행에 대한 칼럼값 중 하나라도
NaN일 경우 해당 행을 삭제한다.
결치값 (NaN)을 다른 숫자로 대체
두 번째 방법은 결치값을 다른 숫자로 대체하는 것이다.
가장 이상적인 방법은 Machine Learning기법을 통해 결치값을 예측하여 값을 채워넣는것이다.
또한, 데이터에 대한 해당 칼럼(변수)의 평균값이나 중위값 등등 이런 통계치도 상황에 따라 괜찮은 대안이 될 수 있다.
가장 기피해야할 방법중 하나는 임의의 수를 분석자가 직접 정해서 넣는 것인데, 이를테면 그냥 NaN을 0으로 대체하는 등 이런 논리적이지 못한 방법은 기피해야함을 인지하자!
하지만 여기서는 우선 0으로 대체를 해보겠다.
1
2
3
4
5
6
7
8
9
10
11
12
df2 = df.fillna(value=0)
display(df2)
"""
A B C D E
2021-08-01 5 8 9 5 7
2021-08-02 0 0 1 7 0
2021-08-03 6 9 2 4 4
2021-08-04 5 2 4 2 0
2021-08-05 4 7 7 9 2
2021-08-06 1 7 0 6 0
"""
이렇게 결치값이 0으로 대체된 것을 볼 수 있다.
Q. E column의 값이 NaN인것을 찾아 A, B column의 값을 출력하라.
어떤식으로 로직을 짜야할까? 우선 NaN에 관해선 == 연산자를 사용할 수 없다.
isnull()이라는 함수를 이용해서 NaN을 찾자!
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
31
32
33
display(df.isnull()) # 전체 데이터 프레임에 대해서 boolean mask가 나옴.
"""
A B C D E
2021-08-01 False False False False False
2021-08-02 False False False False True
2021-08-03 False False False False False
2021-08-04 False False False False True
2021-08-05 False False False False False
2021-08-06 False False False False True
"""
# 이번엔 'E'칼럼에서만 NaN을 찾아보자
display(df.isnull()['E']) # series로 리턴
display(df['E'].isnull()) # 위와 똑같은 값을 리턴
"""
2021-08-01 False
2021-08-02 True
2021-08-03 False
2021-08-04 True
2021-08-05 False
2021-08-06 True
Freq: D, Name: E, dtype: bool
"""
# 인덱싱으로 찾아보자.
display(df.loc[ df.isnull()['E'], ['A', 'B'] ])
"""
A B
2021-08-02 0 0
2021-08-04 5 2
2021-08-06 1 7
"""
# 이렇게 NaN 값이 있는 행에 대해서 A, B 컬럼만 출력하였다.
이상치 Handling
이번엔 NaN 말고 이상치를 바꿔보자.
학생들의 성적이 s라는 pandas Series에 기록되어 있다고 가정을 해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
s = pd.Series([97, 50, 78, 89, 45, -20, 80]) # 성적이라고 하자.
# 영어성적이라고 간주를 한다면, 이상한 값이 하나 들어가있다.
# 성적이 어떻게 0점 밑으로 떨어질 수 있겠는가???
# 이럴 경우, 이상치를 가만히 놔두면 집계함수등 기본적인 통계치에 영향을 미치기 때문에
# 대체를 해주던 삭제를 해줘야한다.
new_s = s.replace(-20, 100) # replace로 값을 바꿔주자.
print(new_s)
"""
0 97
1 50
2 78
3 89
4 45
5 100
6 80
dtype: int64
"""
이런식으로 replace 메서드를 사용하여 다룰수 있다.
거듭 말하지만 어떤 값으로 바꿔주느냐는 처한 상황에 맞는 logic에 근거하여 유추하여야한다.
포스팅 끗. 👋