머신러닝, 빅데이터 사용에 있어 데이터 전처리 과정은 필수 과정이다.
누락된 데이터는 없는지 데이터는 어떤 형태로 존재하고 있는지 면밀히 확인해야 `처리` 과정에서 문제를 사전에 차단할 수 있다.
Null 처리는 전처리 과정에서 무엇보다 중요하다. Pandas 에서 null 데이터를 어떻게 처리하는지 알아보도록 한다.
Pandas에서 처리하는 Null 데이터
- numpy.NaN, numpy.NaT, None
Pandas에서는 numpy.inf ( infinity ), '' (empty string)은 Null이 아닌것으로 취급한다.
개발 환경
- Python 3.9
- Pandas 1.2.0
테스트 DataFrame 준비
df = pd.DataFrame(dict(age=[np.NaN, np.NaN, 6],
born=[pd.NaT, pd.Timestamp('1939-05-27'),
pd.Timestamp('1940-04-25')],
name=[np.NaN, 'Batman', ''],
toy=[None, 'Batmobile', 'Joker']))
info()
DataFrame의 info함수는 데이터의 개략적인 정보를 파악하는데 유용하다.
non-null count 는 null 이 아닌 데이터의 총계이다.
df.info(null_counts=True)
# OUTPUT
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 age 1 non-null float64
1 born 2 non-null datetime64[ns]
2 name 2 non-null object
3 toy 2 non-null object
dtypes: datetime64[ns](1), float64(1), object(2)
memory usage: 224.0+ bytes
isna()
- null인 데이터는 True, 아니면 False를 반환한다. ( isnull과 동일 )
df[df.age.isna()]
# OUTPUT
age born name toy
1 NaN 1939-05-27 Batman Batmobile
notna()
- null이 아닌 데이터는 True, 아니면 False를 반환한다.
df[df.age.notna()]
# OUTPUT
age born name toy
0 5.0 NaT Alfred None
2 6.0 1940-04-25 Joker
dropna()
DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
- null이 존재하는 데이터를 삭제한다.
# 1
df.dropna()
# OUTPUT
age born name toy
2 6.0 1940-04-25 Joker
# 2
df.dropna(subset=['age']) # age가 null인 데이터를 모두 지운다.
# OUTPUT
age born name toy
0 5.0 NaT Alfred None
2 6.0 1940-04-25 Joker
# 3
df.dropna(axis=1) # 컬럼(axis=1) 기준으로 null이 포함된 데이터를 모두 지운다.
#OUTPUT
name
0 Alfred
1 Batman
2
# 4
df.dropna(inplace=True) # 삭제된 DataFrame을 반환치 않고 바로 반영한다.
- how='all' 파라미터는 aixs 옵션에 따라 모든 row나 column이 null 일때 삭제한다.
삭제 후 인덱싱 재처리( reindex )
- 데이터 삭제 후 인덱싱을 재처리 해야 할 필요가 있다. 이때 reset_index 함수를 사용한다.
df[df.age.notna()].reset_index()
# OUTPUT
index age born name toy
0 0 5.0 NaT Alfred None
1 2 6.0 1940-04-25 Joker
- 파라미터로 drop=True를 전달하게 되면 기존 index를 갖고 있는 index 컬럼을 지운다.
df[df.age.notna()].reset_index(drop=True)
# OUTPUT
age born name toy
0 5.0 NaT Alfred None
1 6.0 1940-04-25 Joker
Null 데이터 변경
- fillna 함수를 사용하여 na 데이터를 변경할 수 있다.
df.age = df.age.fillna(0)
df
# OUTPUT
age born name toy
0 0.0 NaT NaN None
1 0.0 1939-05-27 Batman Batmobile
2 6.0 1940-04-25 Joker
- 파라미터 method='bfill' | 'ffill'을 사용하여 인덱스 상에 앞(ffill), 뒤(bfill) 데이터로 채운다.
df.fillna(method='bfill')
# OUTPUT
age born name toy
0 6.0 1939-05-27 Batman Batmobile
1 6.0 1939-05-27 Batman Batmobile
2 6.0 1940-04-25 Joker
시계열 자료의 Null 치환
- 시계열 데이터처럼 연속적인 특징을 갖는 컬럼 중 Null 이 존재할 때 어떻게 처리해야 할까 ? bfill, ffill ? zero ? 아니면 평균 ? 다음 그래프를 보고 판단해보자. ( matplotlib library가 설치 되어야 한다. )
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["legend.loc"] = "upper center"
# 자료 초기화
y = pd.Series([1, 4, 2, 4, np.NaN, np.NaN, 7, 5, 4, np.NaN, np.NaN, 1, 2])
x = np.arange(0, len(y))
# 차트 생성
fig, ax = plt.subplots(nrows=1, ncols=4, figsize=(25,3))
ax[0].plot(x, y.fillna(0), color='red', label='updated')
ax[0].plot(x, y, label='original')
ax[0].set_title('zero')
ax[1].plot(x, y.fillna(y.mean()), color='red')
ax[1].plot(x, y)
ax[1].set_title('mean')
ax[2].plot(x, y.ffill(), color='red')
ax[2].plot(x, y)
ax[2].set_title('ffill')
ax[3].plot(x, y.interpolate(), color='red')
ax[3].plot(x, y)
ax[3].set_title('interpolate')
fig.legend()
- 중간중간에 데이터를 Null로 만든 샘플을 준비 했다. Null을 -0(zero), 평균(mean), ffill, 보간(interpolate)처리한 값은 빨간색 선분으로 표시했다.
- 보는것처럼 연속적인 값을 갖는 데이터는 보간처리( interpolate ), 평균( mean )처리 된 그래프가 적합하다. - 데이터 특징에 맞게 알맞은 치환방법을 선택한다.
'python > Pandas' 카테고리의 다른 글
Pandas query 사용, 다중 조건, Like 검색 등 예제 (0) | 2022.11.09 |
---|---|
Pandas - 컬럼의 고유 값 및 고유값 count 찾기 - 이런저런 방법들! (0) | 2021.03.03 |