목차
1. 개요
데이터 분석에서 결측치는 피할 수 없는 문제입니다. 센서 오작동, 사용자의 미입력, 크롤링 실패 등 다양한 이유로 누락된 값이 생기며, 이를 제대로 처리하지 않으면 분석 결과가 왜곡될 수 있습니다. Pandas는 결측치를 탐지하고, 채우거나 제거하는 강력한 함수들을 제공합니다.
이번 글에서는 isna()
, notna()
, fillna()
, dropna()
, interpolate()
함수들을 중심으로 결측치 처리의 모든 것을 실습과 함께 정리해봅니다.
2. 내용
2-1. 결측치란?
Pandas에서 결측치는 일반적으로 np.nan
(Not a Number)으로 표현됩니다. 숫자형, 문자열, 날짜 등 어떤 타입에도 NaN
이 들어갈 수 있습니다. 이 값은 산술연산이나 조건 비교에 예외적인 처리를 유발하므로 반드시 확인 및 처리해야 합니다.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'Name': ['Alice', 'Bob', 'Charlie', None],
'Age': [25, np.nan, 35, 40],
'Score': [88.5, 92.0, None, 70.0]
})
print(df)
Name Age Score
0 Alice 25.0 88.5
1 Bob NaN 92.0
2 Charlie 35.0 NaN
3 None 40.0 70.0
2-2. isna()
isna()
함수는 각 요소가 결측치인지 여부를 True/False
로 반환합니다. 결측치 필터링, 개수 확인 등에 자주 사용됩니다.
print(df.isna())
Name Age Score
0 False False False
1 False True False
2 False False True
3 True False False
결측치 개수만 보고 싶을 땐 sum()
을 사용합니다.
print(df.isna().sum())
Name 1
Age 1
Score 1
dtype: int64
2-3. notna()
notna()
함수는 isna()
의 반대 개념으로, 결측치가 아닌 값에 대해 True
를 반환합니다. 조건 필터링과 함께 자주 쓰입니다.
print(df[df['Score'].notna()])
Name Age Score
0 Alice 25.0 88.5
1 Bob NaN 92.0
3 None 40.0 70.0
2-4. 결측치 탐색 활용 예제
# 하나라도 NaN이 있는 행
print(df[df.isna().any(axis=1)])
Name Age Score
1 Bob NaN 92.0
2 Charlie 35.0 NaN
3 None 40.0 70.0
# 모든 열이 NaN인 행만 추출 (예: 완전한 결측행)
df_all_na = df[df.isna().all(axis=1)]
print(df_all_na)
이런 방식은 결측치 분포를 파악하거나, 분석 대상에서 제외할 행을 정할 때 유용합니다.
2-5. fillna()
fillna()
는 결측치를 사용자가 지정한 값으로 대체하는 함수입니다. 평균, 중간값, 이전 값, 특정 상수 등 다양한 방식으로 결측값을 채울 수 있어 매우 유연하게 사용됩니다.
# 평균으로 결측치 대체
mean_score = df['Score'].mean()
df_filled = df.fillna({'Score': mean_score})
print(df_filled)
Name Age Score
0 Alice 25.0 88.50
1 Bob NaN 92.00
2 Charlie 35.0 83.50
3 None 40.0 70.00
지정된 방향으로 결측치 채우기 (ffill, bfill)
# 이전 값으로 채우기 (forward fill)
print(df.fillna(method='ffill'))
Name Age Score
0 Alice 25.0 88.5
1 Bob 25.0 92.0
2 Charlie 35.0 92.0
3 Charlie 40.0 70.0
# 이후 값으로 채우기 (backward fill)
print(df.fillna(method='bfill'))
Name Age Score
0 Alice 25.0 88.5
1 Bob 35.0 92.0
2 Charlie 35.0 70.0
3 None 40.0 70.0
채울 수 있는 값이 없을 경우에는 그대로 NaN이 유지되며, limit
옵션을 통해 채울 횟수를 제한할 수도 있습니다.
2-6. dropna()
dropna()
는 결측치를 포함한 행이나 열을 삭제하는 함수입니다. 단순하지만 강력한 기능이며, 분석의 목적과 데이터 특성에 따라 신중하게 사용해야 합니다.
# 하나라도 NaN이 있으면 해당 행 삭제
print(df.dropna())
Name Age Score
0 Alice 25.0 88.5
# 모든 값이 NaN인 행만 삭제
df2 = pd.DataFrame({
'A': [np.nan, np.nan, 3],
'B': [np.nan, 2, 3]
})
print(df2.dropna(how='all'))
A B
1 NaN 2.0
2 3.0 3.0
열 단위로 결측치가 많은 열을 제거할 수도 있음
print(df.dropna(axis=1))
Score
0 88.5
1 92.0
2 NaN
3 70.0
📌 결측치 처리 전략 요약
- 분석 대상에 따라 행 삭제 (dropna) → 데이터 양이 충분할 때
- 이전/다음 값으로 채우기 (ffill, bfill) → 시계열 데이터에 적합
- 평균/중간값으로 채우기 → 수치형 변수 보정
- 모델링에 따라 별도 라벨 지정 → NaN을 따로 의미 있는 값으로 인코딩
2-7. interpolate()
interpolate()
는 결측치를 선형 보간법 등으로 자동 채워주는 함수입니다. 시계열, 연속형 데이터 처리에 매우 강력하며, method
옵션으로 다양한 방식의 보간이 가능합니다.
df_interp = pd.DataFrame({
'Temperature': [23.5, np.nan, 24.8, np.nan, 25.6]
})
print(df_interp.interpolate())
Temperature
0 23.5
1 24.15
2 24.8
3 25.2
4 25.6
선형(linear) 외에도 다양한 보간 방법이 존재합니다.
# index 기준으로 보간
df_interp.interpolate(method='index')
# 시간 간격에 따라 보간 (DatetimeIndex 필요)
# df.interpolate(method='time')
limit_direction
옵션을 통해 앞/뒤 한쪽 방향으로만 채울 수도 있으며, limit
으로 최대 보간 개수도 설정할 수 있습니다.
df_interp.interpolate(limit=1, limit_direction='forward')
📊 실전 예제: 시계열 데이터의 결측값 보간
date_rng = pd.date_range(start='2023-01-01', periods=6, freq='D')
df_ts = pd.DataFrame({'value': [10, np.nan, np.nan, 13, np.nan, 15]}, index=date_rng)
print(df_ts)
value
2023-01-01 10.0
2023-01-02 NaN
2023-01-03 NaN
2023-01-04 13.0
2023-01-05 NaN
2023-01-06 15.0
# 시간 기준 보간
print(df_ts.interpolate(method='time'))
value
2023-01-01 10.00
2023-01-02 11.00
2023-01-03 12.00
2023-01-04 13.00
2023-01-05 14.00
2023-01-06 15.00
3. 결론
이번 글에서는 Pandas에서 결측치를 처리하기 위한 전방위적 방법들을 다뤘습니다. isna
, notna
로 결측값을 탐색하고, fillna
, dropna
, interpolate
를 통해 데이터를 정제하는 것은 모든 분석 작업의 기본이자 핵심입니다.
결측치 처리는 단순한 대체를 넘어서 모델링, 예측 정확도, 통계 해석에 큰 영향을 미치므로, 데이터 특성과 목적에 맞는 전략을 세워 적용해야 합니다. 특히 interpolate()
는 시계열 분석에서 강력한 무기가 될 수 있습니다.
데이터의 결측 상태를 무시하지 말고, 지금 소개한 함수들을 적극적으로 활용하여 분석의 신뢰성과 정확도를 높여보세요.
'Pandas' 카테고리의 다른 글
[Pandas] 열 추가·삭제·변경 함수 정리 (assign, drop, rename,insert) (0) | 2025.04.17 |
---|---|
[Pandas] 데이터 필터링과 조건 선택 함수 정리 (boolean indexing, query, isin 등) (0) | 2025.04.16 |
[Pandas] 데이터 선택과 인덱싱 함수 정리 (loc, iloc, at, iat 등) (0) | 2025.04.16 |
[Pandas] 데이터프레임 생성 및 확인 함수 정리 (pd.DataFrame, head(), info(), tail(), describe()) (0) | 2025.04.15 |