[Python] Pandas: 5. 결측값 처리

Jae Gyeong Lee·2024년 4월 24일

1. 결측값

1.1. NaN (Not a Number)

  • 표현되지 않은 부동소수점 값, float 타입
np.nan

1.2. None

  • 존재하지 않음(Null)을 의미, NoneType 타입
  • 빈 list, dict, set, str, 0, False이 해당
None

-> Pandas는 결측값을 찾고/제거하고/대체할 때, NaN과 None을 동일하게 처리(None을 NaN으로 자동 변경)
-> Python에서 NA(Not Available), NaN(Not a Number), Null은 모두 같은 표현

# pd.NA == <NA>
# np.nan == NaN
# None == None
pd.DataFrame([None, np.nan])

>>
 0
NaN
NaN

1.3. 공백

  • 경우에 따라 공백도 결측값에 해당될 수 있음
  • 공백은 NaN으로 변환한 뒤, 처리
# r'^\s*$' : 문자열의 시작 ~ 끝 사이에 아무런 값도 없거나, 공백만 있는 경우
# np.nan : 설정한 패턴에 해당되는 것을 np.nan으로 바꾸겠다는 것
# regex=True : 설정한 패턴을 regex로 해석하겠다는 의미
# inplace=True : 원본 df를 변경하겠다는 의미

df.replace(r'^\s*$', np.nan, regex=True, inplace=True)

2. 결측값 확인

.isna(), .notna()
  • DataFrame 내 결측값이 있는지 확인하고자 할 때 사용하는 메서드

2.1. .isna()

  • DataFrame 내 결측값인 것을 확인 후, 결과를 True/False로 반환
  • .isna()의 별칭: .isnull()
pd.isna('test')
>> False
pd.isna(pd.NA)
>> True
pd.isna(np.nan)
>> True
pd.isna(None)
>> True

2.2. .notna()

  • DataFrame 내 결측값이 아닌 것을 확인 후, 결과를 True/False로 반환
  • .notna()의 별칭: .notnull()
pd.notna('test')
>> True
pd.notna(pd.NA)
>> False
pd.notna(np.nan)
>> False
pd.notna(None)
>> False

3 ~

import pandas as pd
import numpy as np

data = {
         'A': ['     ', 'b', np.nan, 'd', 'e'],
         'B': ['f', 6, 'g', '  ', 'i'],
         'C': [7, 'k', np.nan, None, 'm'],
         'D': ['n', None, 'o', 9, 'p'],
         'E': [np.nan, 'r', 10, None, '']
       }

df = pd.DataFrame(data)
df

>>>
	A	B	C	D	E
0		f	7	n	NaN
1	b	6	k	None	r
2	NaN	g	NaN	o	10
3	d		None	9	None
4	e	i	m	p	

3. DataFrame 내 결측값 찾기

3.1. .info()

  • DataFrame 전체에 대한 요약 정보 출력
    • Column: 각 column명
    • Non-Null Count: 해당 column의 결측값이 아닌 행의 수
    • Dtype: 해당 column의 데이터 타입(int, float, object 등
  • 각 열에 몇개의 결측값이 있는지 확인할 수 있음
    • (전체 행의 수) - (결측값이 아닌 행의 수)
    • (전체 행의 수)는 df.shape를 통해 확인
df.info()

>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   A       4 non-null      object
 1   B       5 non-null      object
 2   C       3 non-null      object
 3   D       4 non-null      object
 4   E       3 non-null      object
dtypes: object(5)
memory usage: 332.0+ bytes

3.2. .isna(axis=0).sum()

  • DataFrame 내 각 column/row 결측값 개수 확인
  • axis=0 : 행(row) 방향으로 동작, 각 열(column)의 모든 행(row)에 대해 동작
  • axis=1 : 열(column) 방향으로 동작, 각 행(row)의 모든 열(column)에 대해 동작
df.isna().sum() #column별 (default: axis=0)
df.isna().sum(axis=1) #row별
  • 특정 column/row 결측값 확인
#특정 column    
df['A'].isna() # column label이 'A'에 해당되는 데이터 중, 결측값이 있는지 확인

>>>
0    False
1    False
2     True
3    False
4    False
Name: A, dtype: bool
#특정 row
df.loc[0].isna() # row label이 0에 해당되는 데이터 중, 결측값이 있는지 확인

>>>
A    False
B    False
C    False
D    False
E     True
Name: 0, dtype: bool

4. DataFrame 내 결측값 삭제

.dropna()

4.1. 해당되는 row|column 삭제(axis=0|axis=1)

  • 활용 parameter: axis
default: axis=0
  • 결측값이 존재하는 row 삭제
df.dropna() #(default: axis=0)

>>>
	A	B	C	D	E
4	e	i	m	p	
  • 결측값이 존재하는 column 삭제
df.dropna(axis=1)

>>>
	B
0	f
1	6
2	g
3	
4	i

4.2. 삭제할 대상의 조건 설정(any|all)

  • 활용 parameter: how
default: how='any'
  • {row}에 하나라도 결측값이 존재하면 해당 {row} 삭제
df.dropna()
  • {row}가 모두 결측값이면 해당 {row} 삭제
df.dropna(how='all')
  • {column}이 모두 결측값이면 해당 {column} 삭제
df.dropna(axis=1, how='all')

5. DataFrame 내 결측값 변환

  • 명목형 변수

    • 예측값, 최빈값(mode), domain knowledge 활용
  • 연속형 변수

    • mean(평균값), median(중앙값), domain knowledge 활용

5.1. fillna('변환할 값')

  • fillna 함수 인자로 넣은 값으로 결측값이 변환됨
df.fillna('변환')

>>>
    A	B	C	D	E
0		f	7	n	변환
1	b	6	k	변환	r
2	변환	g	변환	o	10
3	d		변환	9	변환
4	e	i	m	p	

5.2. replace(np.nan, '변환할 값')

df.replace(np.nan, '변환')

>>>
    A	B	C	D	E
0		f	7	n	변환
1	b	6	k	변환	r
2	변환	g	변환	o	10
3	d		변환	9	변환
4	e	i	m	p	

참고.

#None -> NaN으로 변환
#판다스는 어차피 NaN과 None을 동일하게 처리함. 시각적으로 변하는 것,
df.fillna(np.nan)

#공백값을 -> NaN으로 변환
df.replace(r'^\s*$', np.nan, regex=True, inplace=True)
profile
안녕하세요 반갑습니다. 공부한 내용들을 기록하고 있습니다.

0개의 댓글