― 이대로만 해도 ‘그나마’ 안 망한다 ―
데이터 분석을 하다 보면 이런 말 자주 듣습니다.
“아 그거 결측 많아요. 그냥 평균으로 넣었어요.”
“결측치 많아서 모델이 안 돌아가요.”
“삭제했는데 성능 왜 이러죠?”
결측치는 분석가의 발목을 붙잡는 은근한 복병입니다.
실제 업무에선 단순히 "채운다"나 "지운다"로는 해결 안 됩니다.
결측이 왜 생겼고, 어떤 종류고, 무엇을 위해 다루는지에 따라
전략이 완전히 달라져야 합니다.
1️⃣ 실무에서 마주치는 결측치, 이건 알아야 합니다
종류 | 설명 | 예시 | 실무적 함의 |
MCAR (Missing Completely at Random) | 완전히 무작위 결측 | 설문 중 실수로 빠뜨림 | 제거해도 영향 적음 |
MAR (Missing at Random) | 특정 변수에 따라 결측 확률 다름 | 나이 많은 응답자가 소득을 잘 안 씀 | 보정 가능, 조심 필요 |
MNAR (Missing Not at Random) | 결측 자체가 의미 있음 | 소득이 높거나 낮을수록 의도적으로 무응답 | 삭제하면 바이어스 발생 |
💡 포인트:
결측은 단순한 '빈칸'이 아니라, 분석을 왜곡할 구조적 신호입니다.
그걸 무시하면 모델도 해석도 망가집니다.
2️⃣ 실무에서 생각할 것:
‘어떻게 채울까?’보다 ‘왜 채우는가’
- 통계 보고용인가? → 단순 대체도 OK (e.g., mean, median)
- 예측 모델인가? → 예측 성능 중심 (모델 기반 대체)
- 인과 추정 또는 해석 중심 모델인가? → 결측이 bias를 만들 수 있음. Multiple Imputation 필수
❗ 평균 넣으면? → 분산 줄고, 계수 왜곡, p-value 망가지고,
결과는 믿을 수 없게 됩니다.
3️⃣ 실무에서 자주 쓰는 결측치 처리 전략
전략 | 사용 시점 | 실전 코드 | 주의사항 |
삭제(drop) | 결측 비율 5% 이하, MCAR 추정 시 | df.dropna(subset=['col']) | 정보 손실, 표본 감소 |
단순 대체 | 통계 보고용, 단순 분포일 때 | SimpleImputer(strategy='mean') | 분포 왜곡, bias 가능 |
시계열 보간 | 순서 있는 시계열 데이터 | df['col'].interpolate(method='time') | 외삽 주의 |
KNN 보간 | 변수 간 거리로 대체 가능 시 | KNNImputer(n_neighbors=5) | 스케일링 필수 |
다중 대체 (Multiple Imputation) | 해석, 인과추론 시 | IterativeImputer() 또는 R mice() | 수렴 확인, 다중 분석 필요 |
4️⃣ 실무자의 체크리스트 ✅
- 결측치가 무작위인가? (MCAR or MAR or MNAR)
- 해당 변수는 모델의 핵심 변수인가?
- 결측 처리 방식이 해석에 어떤 영향을 미칠까?
- 결측 처리가 파이프라인 어디에 위치하는가? (스케일링, 인코딩 전후)
- 모델 목적은 예측인가 해석인가?
🔍 결측치가 무작위인가? (MCAR or MAR or MNAR)
→ 이건 통계적 판단 + 도메인 해석의 조합이 필요합니다.
결론부터 말하면, 100% 자동으로 판단해주는 검사는 없습니다.
하지만, 실무에서는 다음 3가지 단계적 접근으로 꽤 합리적인 판단이 가능합니다.
✅ Step 1. MCAR 여부 판단: 무작위 결측인지 검정
👉 Little’s MCAR Test
- 데이터셋 전반에서 결측이 완전히 무작위(MCAR)인지 검정
- 귀무가설: 결측이 무작위로 발생했다
- 유의수준 이하 → MCAR 아님
📌 현실 팁:
- 이 테스트에서 p > 0.05 → MCAR일 수 있음
- 하지만 완전 무작위인 경우는 거의 없습니다. → 대체로 MAR 또는 MNAR임
✅ Step 2. MAR 여부 판단: 다른 변수와 관계 있는가?
"결측 발생이 다른 변수에 따라 달라지는가?" 를 살펴보면 MAR 여부를 추정할 수 있습니다.
📊 예: 결측 마스크를 만들어 분석
- 특정 변수(col2)에 따라 결측 발생(col1_missing)이 차이가 나면 → MAR 가능성↑
- col1_missing ~ col2 + col3 로 로지스틱 회귀해도 좋습니다
🧠 실무 감각 팁
- 결측률이 특정 연령대, 성별, 지역 등에서 집중 → MAR 가능성
- 결측이 데이터 수집 방식, 응답 행태와 연결 → MAR 가능성
df['col1_missing'] = df['col1'].isnull().astype(int)
sns.boxplot(x='col1_missing', y='col2', data=df)
✅ Step 3. MNAR 여부 탐지: 결측 자체가 의미 있는가?
MNAR은 가장 까다롭습니다.
결측된 값이 클수록, 또는 작을수록 결측이 더 잘 발생하는 경우입니다.
📌 방법
- 분석가의 추론, 도메인 지식, 수집 맥락 파악이 핵심입니다
- 예: 소득 높은 사람이 소득 공개를 꺼린다 → 높은 값일수록 결측
- 예: 체중이 급격히 줄어든 환자가 탈락했다 → MNAR 가능
🧠 실무 감각 팁
- 결측 자체를 더미 변수로 만들어 분석에 포함
→ 결측인 사람과 아닌 사람 간 outcome 차이가 유의하다면
→ MNAR일 가능성 있음
df['missing_flag'] = df['col'].isnull().astype(int)
sns.histplot(data=df, x='outcome', hue='missing_flag')
🧩 해당 변수가 모델의 핵심 변수인가?
구분 | 설명 | 처리 전략 | 실무 예시 |
핵심 변수 | 종속변수와 강한 관련성, 해석에 필수 | 결측 제거보단 보존 우선. 모델 기반 대체 고려 | 소득, 나이, 질병 진단 여부 등 |
주요 아님 | 예측 기여도 낮고, 보조 변수 수준 | 결측 비율 높다면 삭제 고려 가능 | 보조 설명 변수, 설문 부가 질문 등 |
🛠️ 실무 팁:
변수 중요도는 모델 feature importance, VIF, 상관분석, 또는 현업과의 협의를 통해 결정하는 게 좋습니다.
🔍 “핵심 변수일수록, 그 값이 비어 있다면 그 행(row)을 아예 제외해야 하지 않나?”
👉 MCAR(무작위 결측)이라면, 제거해도 bias 없으나
MAR/MNAR(체계적 결측)이라면, 제거는 위험하며 selection bias(선택 편항) 발생 가능
👉 분석 목적이 예측/성능 중심이라면, 제거해도 괜찮으나
분석 목적이 인과 해석 중심이라면, 결측 자체가 인과 경로에 포함될 수 있어 보존이 우선임
(즉, 인과 추론에서 Missingness(결측)이 하나의 변수처럼 작용할 수 있음!)
🎯 결측 처리 방식이 해석에 어떤 영향을 미치는가?
처리 방식 | 해석에 미치는 영향 | 해석 중심 분석 시 권장 여부 |
삭제 | 표본 수 감소 → 통계적 검정력 낮아짐 | ❌ |
단순 대체 (평균/중앙값) | 분산 감소 → 계수 및 p-value 왜곡 | ❌ |
모델 기반 대체 (KNN 등) | 공분산 구조 왜곡 가능 | ⚠️ 사용 시 주의 |
Multiple Imputation (다중 대체) | 표준 오차, 신뢰구간 보존 가능 | ✅ 권장 |
결측 자체를 변수화 | 결측 자체의 효과 반영 가능 | ✅ 유용함 (특히 MNAR 추정 시) |
📌 모델 해석이 중요한 경우,
반드시 결측 처리 이후 회귀계수, 표준오차가 어떻게 변했는지 비교해야 합니다.
단순히 AUC만 높다고 좋은 게 아닙니다.
🔄 결측 처리가 파이프라인 어디에 위치하는가?
처리 위치 | 적절 시점 | 이유 |
데이터 분할 전 처리 | ❌ 비추천 | 테스트 데이터 정보 누출 가능성 (data leakage) |
데이터 분할 후, 학습 데이터만으로 imputer 학습 | ✅ 권장 | 누수 방지, 현실 반영 |
스케일링/인코딩과의 순서 | 일반적으로 결측 처리 → 인코딩/스케일링 | 결측이 존재하면 인코딩/스케일링이 오류 발생 |
💡 파이프라인 구성 예시
# 파이프라인 구성 예시
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='mean')), # 먼저 결측 처리
('scaler', StandardScaler()) # 그 다음 스케일링
])
🧠 모델의 목적이 예측인가, 해석인가?
목적 | 결측 처리 전략 | 평가 방식 | 실무 사례 |
예측(Prediction) | 성능 향상이 목적 → KNN, Iterative, 임의값 대체 등 가능 | AUC, RMSE, F1 등 | 보험사 고객 이탈 예측 |
해석(Interpretation) | 계수/효과 추정이 목적 → MI, indicator 사용 | 계수 해석, p-value, 신뢰구간 | 정책 효과 분석, 논문, 공공 보고 |
⚠️ 해석 중심 분석에서 예측 기반 대체법 사용 시, bias로 인해
"정책이 효과 있다"고 잘못 해석할 수 있습니다.
✨ 최종 요약: 실무에서의 결측 전략 결정 플로우
[결측치 발생]
↓
"이 결측이 무작위인가?" → MCAR? MAR? MNAR?
↓
"해당 변수 중요도는?" → 핵심이면 삭제보다 보존
↓
"모델 목적은?" → 예측인가? 해석인가?
↓
"어디서 처리할까?" → 데이터 분할 후, 파이프라인 내에서
↓
[적절한 전략 선택: 삭제, 단순 대체, KNN, MI 등]
↓
"결측 처리 이후 해석에 어떤 변화가 생겼는가?" → 회귀 계수, 오차 확인
Q1 - 결측치와 예측 성능 간의 trade-off, 어떻게 측정할까?
결측을 어떻게 다루느냐에 따라 예측 성능이 요동칩니다.
이를 정량적으로 측정하려면 이렇게 접근하세요:
🔬 Step-by-step 평가 방법
1. baseline 모델
→ 결측치 제거 후 학습
2. 대체 전략1~N 적용
→ 각각 대체한 후 동일 모델 학습
3. 각 모델의 성능 비교
- 회귀: RMSE, R², MAE
- 분류: Accuracy, AUC, F1 Score, PR AUC
4. 차이가 크다면?
→ "결측 처리 전략 자체가 모델 성능을 왜곡할 수 있다"는 신호
5. 검증용 외부 데이터나 교차검증 사용 권장
📌 실제 예시:
# 결측 처리별 성능 비교 예시
for imputer in imputers:
X_imputed = imputer.fit_transform(X)
model.fit(X_imputed, y)
y_pred = model.predict(X_test)
print(imputer.__class__.__name__, roc_auc_score(y_test, y_pred))
결론:
예측 성능이 중요하다면, 결측 처리도 튜닝 대상입니다.
단, 과적합 되지 않도록 교차검증은 필수입니다.
Q2 - 인과추론 및 해석이 중요한 경우, 어떤 방식이 적절할까?
해석이 목적이라면 반드시 다음 중 하나를 고려하세요:
✅ 1. Multiple Imputation (다중 대체)
🔁 "하나의 결측에 대해 여러 개의 그럴듯한 값들을 채워서, 결과의 불확실성까지 고려하는 방식"
(결측이 다른 변수들과 관련 있을 때(MAR), 해석의 정확성과 인과 분석이 중요할 때)
📌 핵심:
- 데이터를 여러 개(보통 5~10개)로 복제하고 결측값을 조금씩 다르게 채움
- 각 데이터셋에서 모델 적합 후 각각 분석
- 회귀 계수, 분산 등 결과를 모은 후 Rubin's Rule를 통해 종합된 추정값과 신뢰구간 계산
🔍 Rubin's Rule:
여러 개의 Multiple Imputation 분석 결과를 하나의 해석 가능한 결과로 결합
회귀계수는 평균 내고, 표준 오차(총 분산)은 각 분석의 오차의 평균과 분석 결과 간 오차를 함께 고려
(불확실성을 반영한 robust한 해석 가능)
📌 Python 예시: (단일 대체지만 방식 유사, R의 mice()가 더 정석적)
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
import pandas as pd
# 예시 데이터
df = pd.read_csv("data.csv")
# 다중 대체
imp = IterativeImputer(random_state=0, max_iter=10)
df_imp = imp.fit_transform(df)
# 다시 데이터프레임으로
df_imp = pd.DataFrame(df_imp, columns=df.columns)
✅ 2. 결측 자체를 분석 변수로 포함 (Missing Indicator Method)
🧭 “결측 여부 자체를 정보로 본다”
즉, 어떤 값이 비어 있었다는 사실 그 자체가 의미 있다고 판단할 때 쓰는 방식
(결측이 단순 실수나 우연이 아닌 경우(MNAR), 가령 소득 낮은 사람이 소득을 숨겼거나 건강이 좋지 않아 검사를 못 받음)
📌 핵심:
- 원래 변수 X1을 더미화하여 X1_missing을 만들고,
X1_missing이 1이면 "이 사람은 X1이 비어 있었던 사람"
- 회귀 계수에서 X1_missing 값이 유의하면,
결측 자체가 outcome에 영향을 줄 수 있다는 뜻!
📌 Python 예시:
# 1. 결측 여부 변수화
df['X1_missing'] = df['X1'].isnull().astype(int)
# 2. 원래 변수 X1은 단순 대체 (예: 평균으로)
from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='mean')
df['X1'] = imp.fit_transform(df[['X1']])
✅ 3. Sensitivity Analysis (결측 편향 민감도 분석)
❗ "결측이 다른 방식으로 채워졌다면 결과가 얼마나 달라졌을까?"를 평가
(결측이 MNAR일 가능성이 높거나, 어떤 결측 처리 방법을 쓸지 확신이 없을 때,
분석 결과의 신뢰성 한계까지 파악하고 싶을 때)
📌 핵심:
- 결측이 어떻게 생겼냐고 가정하느냐에 따라 결과가 어떻게 달라지는지 실험해보는 것
- 가정이 바뀌었을 때 결과가 뒤집힌다면, 민감도가 높다는 뜻이므로 해석에 신중
- E-value, Bias Parameter 등 사용
🔍 E-value:
우리가 관측하지 못한(결측된) X값들이 Y에 영향을 줬을 가능성이 있다면,
그 요인이 얼마나 강한 영향력을 가져야 현재의 효과 추정값이 무력화되는가?
✅ E-value가 클수록: 결측이나 confounding이 있어도 결과는 비교적 robust
❗ E-value가 작으면: 약한 confounder만 있어도 결과가 뒤집힐 수 있음 → 주의
🔍 Bias Parameter:
결측된 집단이 관측된 집단과 얼마나 다르다고 가정할 것인가?를 수치화한 값
예 - 소득이 결측된 사람은 저소득층일 것이라 가정, 이 차이를 수치로 bias parameter = -20(20만원 낮음)
→ bias parameter를 -10, -20, -30 등으로 바꿔보면서 분석 결과를 반복
→ 결과가 크게 흔들린다면, 결측이 결과에 미치는 영향력이 크다는 뜻
💡 실무 팁
- 인과추론이 목적이라면 결측치 처리에서부터 bias 통제가 시작됩니다.
- 단순한 예측 목적이라면 모델 성능만 보겠지만, 해석 목적이라면 처리 과정까지 검토해야 결과의 의미가 있습니다.
✨ 마무리하며
결측치는 그냥 '비어 있는 값'이 아닙니다.
데이터가 보내는 구조적 메시지일 가능성이 있습니다.
“어떻게 채울까?”보다 중요한 건
왜 비었는지, 채우면 무엇이 달라지는지 파악하는 힘입니다.
📌 결측치는 기술이 아니라 태도로 다뤄야 하는 영역입니다.
좋은 분석가는 '값이 비었을 때' 더 똑똑해집니다. 💡
'데이터분석' 카테고리의 다른 글
[데이터분석] 반복측정(longitudinal) 데이터의 두 축: GEE vs GLMM (0) | 2025.05.16 |
---|---|
[생존분석] RMST vs. AFT 모델 완전 정리 (2) | 2025.05.16 |
[데이터분석] 📚 결측치 처리와 인과추론, 함께 이해하기 (0) | 2025.04.26 |
[데이터분석] 📊 이상치(Outlier) 처리, 완전 실무형 정리 (2) | 2025.04.26 |
[메타 분석] (Meta-analysis) 완벽 정리 가이드📚 (0) | 2025.04.21 |