결측치 (Missing Value), 데이터 전처리, Python, 결측치 처리, 결측치 제거, 결측치 대체
결측치(Missing Value)는 데이터 수집 과정에서 다양한 이유로 발생하는 누락된 값을 의미한다. 결측치가 존재하면 통계 분석이나 머신러닝 모델의 정확도가 저하될 수 있으므로 적절한 처리가 필수적이다. 이 장에서는 결측치를 탐지하고 제거하거나 대체하는 다양한 기법을 학습한다. 결측치 처리 방법은 데이터의 특성과 결측치의 패턴에 따라 달라지므로, 각 상황에 맞는 적절한 전략을 선택하는 것이 중요하다.
3.1 데이터 로드 및 결측치 현황 확인
결측치 처리를 시작하기 전에 먼저 데이터를 불러오고 결측치가 어느 컬럼에 얼마나 존재하는지 파악해야 한다.
예제: 데이터 로드 및 결측치 개수 확인
import pandas as pdimport seaborn as sns# 데이터 로드df = sns.load_dataset("penguins")# 컬럼별 결측치 개수 확인df.isna().sum()
species 0
island 0
bill_length_mm 2
bill_depth_mm 2
flipper_length_mm 2
body_mass_g 2
sex 11
dtype: int64
3.2 결측치 비율 확인
결측치의 개수뿐만 아니라 전체 데이터 대비 비율을 확인하면 결측치 처리 전략을 수립하는 데 도움이 된다. 일반적으로 결측치 비율이 5% 미만이면 해당 행을 제거하고, 5~10%인 경우 대체 방법을 고려하며, 10% 이상인 경우 신중한 분석이 필요하다.
예제: 결측치 비율 확인
# 컬럼별 결측치 비율 (%)(df.isna().mean() *100).round(1)
species 0.0
island 0.0
bill_length_mm 0.6
bill_depth_mm 0.6
flipper_length_mm 0.6
body_mass_g 0.6
sex 3.2
dtype: float64
위 결과를 통해 각 컬럼의 결측치 비율을 백분율로 확인할 수 있다. 비율이 낮은 컬럼은 행 제거를, 비율이 높은 컬럼은 대체 방법을 고려한다.
3.3 결측치 제거 (행 삭제)
결측치가 소수이거나 분석에 큰 영향을 미치지 않는 경우, 해당 행을 삭제하는 것이 가장 간단한 방법이다. 다만, 제거로 인한 데이터 손실이 크지 않은지 반드시 확인해야 한다.
3.3.1 결측치가 있는 모든 행 제거
하나라도 결측치가 있는 행을 모두 제거하는 방법이다. 가장 보수적인 접근이지만 데이터 손실이 클 수 있다.
예제: 전체 결측치 행 제거
# 결측치가 하나라도 있는 행 제거df_drop_all = df.dropna()# 제거 후 데이터 크기 확인print(f"원본 데이터: {df.shape}")print(f"결측치 제거 후: {df_drop_all.shape}")
원본 데이터: (344, 7)
결측치 제거 후: (333, 7)
3.3.2 결측치가 특정 개수 이상인 행 제거
전체 컬럼 중 일부만 결측치인 경우 해당 행을 유지하고, 결측치가 많은 행만 제거하는 방법이다.
예제: 결측치가 3개 이상인 행 제거
# 각 행의 결측치 개수 계산df["na_count"] = df.isna().sum(axis=1)# 결측치가 3개 미만인 행만 유지df_row_filtered = df[df["na_count"] <3].drop(columns="na_count")# 제거 후 데이터 크기 확인print(f"결측치 필터링 후: {df_row_filtered.shape}")
결측치 필터링 후: (342, 7)
예제: thresh 파라미터를 사용한 행 제거
# 최소 n개의 비결측값이 있는 행만 유지# 전체 컬럼에서 2개까지 결측치 허용df_thresh = df.dropna(thresh=len(df.columns) -2)print(f"thresh 적용 후: {df_thresh.shape}")
thresh 적용 후: (342, 8)
thresh 파라미터는 행을 유지하기 위해 필요한 최소 비결측값 개수를 지정한다. 예를 들어, 전체 컬럼이 8개인 경우 thresh=6이면 최소 6개의 값이 있어야 행이 유지된다.
3.3.3 특정 컬럼 기준 제거
특정 컬럼의 결측치만 제거하고 싶을 때 사용하는 방법이다. 분석에 필수적인 컬럼의 결측치를 제거할 때 유용하다.
예제: 특정 컬럼 결측치 제거
# sex 컬럼에 결측치가 있는 행 제거df_drop_sex = df.dropna(subset=["sex"])print(f"sex 컬럼 결측치 제거 후: {df_drop_sex.shape}")
sex 컬럼 결측치 제거 후: (333, 8)
여러 컬럼을 동시에 지정할 수도 있다.
# 여러 컬럼 중 하나라도 결측치가 있으면 제거df_drop_multi = df.dropna(subset=["sex", "bill_length_mm"])df_drop_multi.shape
(333, 8)
3.4 수치형 변수 결측치 대체
결측치를 제거하면 데이터가 손실되므로, 특정 값으로 대체하는 방법을 고려할 수 있다. 수치형 변수는 주로 평균, 중앙값, 최빈값 등의 대푯값으로 대체한다.
3.4.1 평균(mean)으로 대체
평균은 데이터의 중심 경향을 나타내는 대표적인 값이다. 다만, 이상치에 민감하므로 이상치가 많은 경우 중앙값 사용을 권장한다.
예제: 단일 컬럼 평균 대체
# 데이터 복사 (원본 보존)df_mean = df.copy()# bill_length_mm 컬럼의 결측치를 평균으로 대체df_mean["bill_length_mm"] = df_mean["bill_length_mm"].fillna( df_mean["bill_length_mm"].mean())# 결측치 확인print(f'결측치: {df_mean["bill_length_mm"].isna().sum()}')
결측치: 0
예제: 다중 컬럼 평균 대체 (방법 1)
# 수치형 컬럼 목록num_cols = ["bill_length_mm","bill_depth_mm","flipper_length_mm","body_mass_g"]df_cols = df.copy()# 여러 컬럼의 결측치를 각각의 평균으로 대체df_cols[num_cols] = df_cols[num_cols].fillna(df_cols[num_cols].mean())# 결측치 확인print(df_cols[num_cols].isna().sum())
df_loop = df.copy()# 반복문을 사용한 평균 대체for col in num_cols: mean_value = df_loop[col].mean() df_loop[col] = df_loop[col].fillna(mean_value)# 결측치 확인print(df_loop[num_cols].isna().sum())