1 정의
분석 모형 (예: bkg_amt ~ age + extra) 에는 포함되지 않지만, 결측 대체 모형에 추가해 imputation 의 정확도를 높이는 변수 (Buisson, 2021, Ch.6).
특징:
- 분석 회귀 식에는 등장 안 함
- 대체 모형의 회귀 식에는 등장
- 결측 변수와 강한 상관 (대체 정확도 향상)
- Outcome 변수와도 상관 (편향 보정)
예: AirCnC 의 Insurance, Active 변수 — 분석 대상은 아니지만 Neuro 의 결측을 보정하는 데 사용.
비유: 면접에서 “나는 이 직무에 안 지원” 이라고 하면서 친구에게 정보 제공.
- 친구는 면접의 일부 아니지만 (auxiliary)
- 그 정보가 다른 후보자 평가에 도움 (정확도 ↑)
분석에서:
- 보조 변수는 분석 결과 (Treatment 효과) 에 안 들어감
- 그러나 결측 대체의 품질을 높임
- 그 결과로 분석 결과가 더 정확
→ “주연” (분석 대상) 과 “조연” (보조 변수) 의 분리. 조연이 주연을 빛나게 함.
2 보조 변수의 활용 시나리오
2.1 1. MNAR 처리 — Child Variable 활용
MNAR 의심 시 (예: Neuro 자체 → Missing_Neuro):
- 표준 MI (mice 의 default) 는 MAR 가정 → MNAR 에 부정확
- 그러나 Neuro 의 child variable (Neuro 의 결과 변수) 를 보조로 추가하면 부분 보정 가능
근거:
- Neuro 의 진짜 값이 child 변수에 영향 (인과 관계)
- Child 변수가 관측됨 → Neuro 의 진짜 값을 부분적으로 추정
- 이 추정이 MNAR bias 를 줄임
CD:
[Neuro] ──→ Child_1 (예: Insurance)
↓ ──→ Child_2 (예: Active)
Missing_Neuro
↓
Observed_Neuro
Child_1, Child_2 가 보조 변수로 추가되면 [Neuro] 의 분포 추정 정확도 ↑.
비유: 사진의 그림자만 보고 물체의 크기 추정.
- 직접 물체를 못 보지만 (Neuro 결측)
- 그림자가 물체와 인과 관계 → 그림자로 물체 추정 가능 (Child 변수 활용)
수식:
\[P(\text{Neuro}_{\text{missing}} \mid \text{Child}_1, \text{Child}_2, \text{other obs}) \approx P(\text{Neuro} \mid \text{Child}_1, \text{Child}_2, \text{other obs})\]
Child 변수가 충분히 정보적이면 (Neuro 와 강한 상관) 이 근사가 정확.
→ MNAR 의 직접 처리 불가능하지만, 우회 (proxy 활용) 로 부분 처리.
2.2 2. AirCnC 사례 — Insurance 와 Active
Buisson 의 AirCnC supplement 데이터:
- Insurance: 고객이 평생 구매한 여행 보험 총액
- Active: 고객 예약의 활성도 numeric measure
이 두 변수의 특징:
- 분석 대상 (bkg_amt 의 인과 분석) 에 직접 포함되지 않음
- Neuroticism 과 강한 상관 (성격이 보험 구매·활동성에 영향)
- bkg_amt 와 약한 상관 (직접 인과 약함)
→ 보조 변수의 ideal 조건. mice 에 추가:
imputation_data <- merge(available_data, supplement)
imp <- mice(imputation_data, m = 20)
# 분석은 bkg_amt ~ age + extra + neuro + ... 만Insurance, Active 가 mice 의 대체 모형에 들어감. 그러나 최종 회귀에는 안 들어감.
이 분리가 가능한 이유:
- Mice 가 각 결측 변수를 다른 모든 변수에 대해 회귀 적합 (대체 모형)
- 이 대체 모형에 보조 변수 포함하면 대체 정확도 ↑
- 그 결과 대체 데이터가 더 정확
- 그 데이터에 분석 회귀 적용 (보조 변수 제외)
→ Mice 의 chained equation 구조가 자연스럽게 보조 변수 활용 가능.
비즈니스 함의: 보조 데이터가 있으면 (Insurance, Active 같은) 무조건 mice 에 포함. 분석에 안 들어가도 손해 없음.
2.3 3. 보조 변수의 선택 기준
| 조건 | 설명 | 예 |
|---|---|---|
| 결측 변수와 강한 상관 | 결측 값을 잘 예측 | Insurance ↔︎ Neuro: r=0.4 |
| Outcome 과 약한 상관 | 분석 결과에 직접 영향 작음 | Insurance ↔︎ Bkg_amt: r=0.1 |
| 결측 적음 | 보조 변수 자체 결측 적어야 | Insurance: 결측 없음 |
| 도메인 의미 | 인과 가설 정당화 | “성격 → 보험 구매” 직관 |
이 조건을 모두 만족하는 변수가 ideal. 하나라도 만족 안 하면 보조 변수로 의심.
만약 보조 변수가 outcome 과 매우 강한 상관이라면?
- 보조 변수가 사실상 outcome 의 mediator
- Imputation 에 포함하면 over-adjustment 위험
- 분석 결과 편향
비유: “친구의 정보로 후보 평가” 상황에서 친구가 사실상 후보의 동업자라면 — 친구 의견이 후보 평가의 객관성을 해침.
해결: 보조 변수를 추가할 때 분석 대상 변수와의 인과 관계 점검. Mediator 또는 collider 의심되면 추가 안 함.
3 대체 수 m 의 결정
3.1 Rubin 의 효율성 분석
m 번 대체의 효율성 (full data 대비):
\[ \text{Efficiency} = \left(1 + \frac{\text{FMI}}{m}\right)^{-1} \]
여기서 FMI (Fraction of Missing Information):
\[ \text{FMI} = \frac{(1 + 1/m) B}{T} \]
(Between 분산 / Total 분산)
해석:
- FMI = 0: 결측 정보 없음 → 효율성 100%
- FMI = 0.5: 결측이 분산의 50% 차지 → 효율성 = 1 / (1 + 0.5/m)
m 이 클수록 효율성 ↑, 하지만 수익 체감.
Rubin (1987) 의 효율성 표:
| FMI m | 5 | 10 | 20 | 50 |
|---|---|---|---|---|
| 0.1 | 98% | 99% | 99.5% | 99.8% |
| 0.3 | 94% | 97% | 98.5% | 99.4% |
| 0.5 | 91% | 95% | 97.5% | 99.0% |
| 0.7 | 88% | 93% | 96.5% | 98.6% |
분석가의 default:
- FMI < 0.3 (대부분 사례): m = 5 충분
- FMI 0.3~0.5: m = 10~20 권장
- FMI > 0.5: m = 30~100 (큰 결측)
AirCnC 사례 (Neuro 50% 결측): FMI 약 0.4 → m = 20 권장.
3.2 FMI 의 추정
FMI 는 m 번 대체 후에 계산 가능 — 먼저 m 을 정해야 FMI 알 수 있음 (chicken-and-egg).
해결:
- 첫 시도: m = 10 으로 시작
- FMI 확인: 출력에서 변수별 FMI 점검
- 재실행 결정:
- FMI 가 모두 낮으면 (< 0.3) → m = 10 유지
- FMI 일부 높으면 (> 0.4) → m = 30 또는 50 으로 재실행
이 절차가 실용적.
FMI 가 0.5 라는 의미:
- “분산의 절반이 결측 불확실성에서 옴”
- “결측이 진짜 분산의 50% 차지”
- 큰 영향
FMI 0.05:
- “결측 영향 거의 없음”
- m 작게 OK
비즈니스 분석가가 보고서에 FMI 명시하면 결측 영향의 정량적 평가 가능.
“본 분석의 Treatment 효과 추정 (β = 1.5) 의 FMI = 0.32. 결측이 분산의 32% 차지. m=20 으로 처리.”
이게 정직한 보고.
3.3 von Hippel 의 권장
von Hippel (2018) 의 더 새로운 권장:
“m 을 결측 비율의 percent 에 맞춰 설정”
예:
- 결측 5%: m = 5
- 결측 25%: m = 25
- 결측 50%: m = 50
이유: 결측 비율 ≈ FMI 의 상한. 보수적이려면 m 을 결측 비율과 같게.
분석가 default 결정:
- 빠른 분석 → Rubin’s 권장 (m = 5~20)
- 보고서·논문 → von Hippel (m = 결측 비율)
3.4 시간 vs 정확성 Trade-off
각 m 마다:
- mice 의 m 번 update (각 변수의 chained equation 계산)
- 각 데이터셋에 회귀 적합
- Rubin pooling
총 시간 = O(m × n × p²) (n = 표본, p = 변수 수)
예: n = 100,000, p = 50:
- m = 5: 1 분
- m = 20: 4 분
- m = 50: 10 분
- m = 100: 20 분
비즈니스 분석에서 시간은 중요. 분석가가 결정:
- 첫 탐색: m = 5 (빠른 결과 보고 알려진 패턴)
- 최종 보고: m = 20~50 (정확도 + 신뢰)
- 논문: m = 50~100 (보수적)
→ 분석 단계에 따라 m 변경 가능.
4 보조 변수 + m 결정 통합 절차
1. 결측 진단 ([E-BUI6-2](./E-BUI6-2-mcar-mar-mnar-diagnosis.qmd))
→ MCAR / MAR / MNAR 가설
2. 보조 변수 식별
- MNAR 의심 시: child variable 추출
- MAR 도 도움: 결측 변수와 강한 상관 변수
- 외부 데이터셋 (supplement) 활용
3. m 의 첫 시도 결정
- 결측 비율 < 10%: m = 5
- 결측 비율 10~30%: m = 10
- 결측 비율 30%+: m = 20+
4. mice 실행 + FMI 확인
- 변수별 FMI 점검
- FMI > 0.4 변수가 있으면 m 증가
5. 분석 + 보고
- Rubin pooling
- 보고서에 m, 보조 변수, FMI 명시
이 절차가 결측 처리의 표준.
5 AirCnC 의 통합 적용
5.1 데이터 결합
import pandas as pd
# 원본 결측 데이터
available_df = pd.read_csv("chap6-available_data.csv")
# 보조 데이터 (Insurance, Active)
supp_df = pd.read_csv("chap6-available_data_supp.csv")
# ID 기준 결합
combined_df = available_df.merge(supp_df, on="customer_id")
print(combined_df.columns.tolist())
# ['customer_id', 'age', 'gender', 'state', 'open', 'extra', 'neuro', 'bkg_amt', 'insurance', 'active']Insurance, Active 가 결측 없음 (supplement 데이터의 특징). 보조 변수로 사용.
5.2 mice 에 보조 변수 포함
library(mice)
# m=20 으로 mice 실행 (Neuro 결측 50% 고려)
imp <- mice(combined_df,
m = 20,
method = c("", "", "logreg", "polyreg", # age, open 결측 없음
"pmm", "pmm", "pmm", # extra, neuro, bkg_amt
"", ""), # insurance, active
seed = 42)
# 분석은 보조 변수 제외 (Insurance, Active 안 씀)
fit <- with(imp, lm(bkg_amt ~ age + open + extra + neuro + gender + state))
# Pooled 결과
summary(pool(fit))이 코드의 핵심:
mice()가 모든 변수 포함 (Insurance, Active 도)with(imp, lm(...))가 분석 회귀에는 보조 변수 제외pool()이 Rubin pooling
Python 의 mice 는 categorical 처리에 한계. one-hot encoding 후 사용:
from statsmodels.imputation import mice as mi
import statsmodels.api as sm
import pandas as pd
# Categorical 변수 dummy 처리
combined_dummies = pd.get_dummies(combined_df, columns=["gender", "state"])
# mice
mice_data = mi.MICEData(combined_dummies)
# 분석 모형 정의 (보조 변수 제외)
formula = "bkg_amt ~ age + open + extra + neuro + gender_F + state_B + state_C"
mice_model = mi.MICE(formula, sm.OLS, mice_data)
# m = 20 번 fit
result = mice_model.fit(n_imputations=20, n_skip=10)
print(result.summary())출력에 FMI 자동 포함. 변수별 FMI 점검:
- FMI 작음 (< 0.2): m = 20 충분
- FMI 큼 (> 0.4): m = 50 으로 재실행
5.3 FMI 출력 해석
coef. Std.Err. t P>|t| [0.025 0.975] FMI
Intercept 120.36 8.87 13.57 0.0000 102.98 137.73 0.4712
age -1.13 0.17 -6.56 0.0000 -1.47 -0.79 0.2689
open 3.13 0.89 3.51 0.0004 1.38 4.88 0.1723
extra 11.13 1.02 10.87 0.0000 9.12 13.13 0.3855
neuro -4.59 1.80 -2.55 0.0106 -8.11 -1.07 0.4219
gender_M 65.96 4.82 13.69 0.0000 56.52 75.41 0.4397
gender_F 54.40 4.68 11.62 0.0000 45.22 63.57 0.4154
state_A 40.94 3.91 10.47 0.0000 33.28 48.59 0.3921
state_B 37.35 4.07 9.17 0.0000 29.37 45.33 0.2904
state_C 42.07 3.86 10.89 0.0000 34.50 49.65 0.2298
FMI 해석:
- Neuro: FMI = 0.42 → 결측이 Neuro 계수의 분산의 42% 차지. 큰 영향.
- Extra: FMI = 0.39 → 비슷
- Open: FMI = 0.17 → 작음 (결측 없으므로)
- State_C: FMI = 0.23 → 작음 (state 결측 35.5% 이지만 effect 작음)
→ Neuro, Extra 의 FMI 가 0.4 부근이므로 m = 20 적절. m = 5 였으면 부정확.
가설: FMI ≈ 결측 비율?
실제: FMI ≤ 결측 비율 (대체로).
이유:
- 결측 비율 50% 라도 보조 변수로 잘 예측되면 FMI < 50%
- 결측 비율 5% 라도 예측 어려우면 FMI 가 그 이상일 수도 (드물게)
AirCnC 의 Neuro:
- 결측 50%, FMI 42%
- 보조 변수 (Extra, Insurance 등) 가 Neuro 를 부분 예측 → FMI 가 결측 비율보다 작음
이 패턴이 의미: 보조 변수가 mathematical 효과를 가짐. FMI 줄이는 도구.
→ 좋은 보조 변수 발굴 = FMI 감소 = 분석 정확도 ↑.
6 Deterministic MNAR 의 추가 처리
E-BUI6-2 에서 발견: Neuro = 4 인 사람들 모두 결측.
표준 mice 가 처리 못 함 (관측 데이터에 4 값 없음).
Buisson 의 권장:
- 도메인 가정: “결측은 Neuro ≤ 4”
- mice 의 mass.norm 또는 ri 메소드 (R) 사용 — 분포 가정 활용
- Truncated normal sampling
# R: 임계값 정보 활용
imp <- mice(combined_df,
m = 20,
method = c("", "", "logreg", "polyreg",
"norm.boot", # extra: normal with bootstrap
"norm.boot", # neuro: normal with bootstrap (truncated logic added later)
"pmm",
"", ""),
seed = 42)또는 Python 에서 manual:
# 결측 행에 대해 0~4 균등 분포로 sampling
miss_idx = combined_df["neuro"].isnull()
combined_df.loc[miss_idx, "neuro"] = np.random.uniform(0, 4, miss_idx.sum())이 방법이 deterministic MNAR 의 특수 처리.
Deterministic MNAR 의 처리 결과는 분석가의 가정 에 의존.
가정:
- “결측은 Neuro ≤ 4” — 정확하면 분석 정확
- “결측 분포가 0~4 균등” — 정확하면 분석 정확
만약 진짜 분포가 다르면 (예: 0~4 의 정규) 결과 편향.
Sensitivity analysis:
- 균등 분포 가정 → 결과 A
- 정규 분포 가정 → 결과 B
- 두 결과 비교
만약 A 와 B 가 비슷 → 결과 robust. 다르다 → 가정에 민감, 추가 정보 필요.
→ MNAR 처리는 결국 가정의 sensitivity 분석. 최종 결과의 confidence 가 가정에 의존.
7 분석 보고서의 의무
비즈니스 분석 보고서·논문에 다음 명시:
결측 처리:
- 결측 비율 (변수별)
- Rubin 분류 진단 (변수별)
- 처리 방법: Multiple Imputation (m=20, mice 패키지)
- 보조 변수: Insurance, Active (분석에는 미포함)
- FMI: 변수별 (Neuro 0.42, Extra 0.39, 기타 < 0.3)
- 가정: MAR (Neuro 의 deterministic MNAR 가능성은 sensitivity analysis 로 점검)
- Sensitivity: 결측 메커니즘 가정 변경 시 결과 robust
CONSORT, STROBE 등 가이드라인이 이 명시 의무화.
분석가가 결측을 명시 안 하면:
- 독자가 결과의 한계를 모름
- 다른 분석가가 재현 불가
- 비즈니스 의사결정의 risk 모름
정직한 보고:
- 결측 처리의 가정·도구·결과 모두 명시
- 가정 위반 시 결과 변화 (sensitivity)
- 분석가의 결정 trace 가능
이게 분석 신뢰성의 기반.
→ “이상적이지 않은 결과를 정직하게” 가 “이상적인 결과를 가짜로” 보다 가치 있음.
8 코드 예시 — Python 으로 통합 워크플로
8.1 1. 보조 변수 식별
import numpy as np
import pandas as pd
from scipy.stats import pearsonr
def identify_auxiliary_variables(df, target_var, outcome_var, candidate_vars,
min_target_corr=0.2, max_outcome_corr=0.4):
"""
보조 변수 후보 식별.
Parameters
----------
target_var : 결측 있는 변수
outcome_var : 분석 대상 (Y)
candidate_vars : 보조 변수 후보 목록
min_target_corr : 결측 변수와의 최소 상관
max_outcome_corr : Outcome 과의 최대 상관 (over-adjustment 회피)
Returns
-------
list of (var, target_corr, outcome_corr)
"""
results = []
target_obs = df[df[target_var].notna()][target_var].values
outcome_obs = df[df[target_var].notna()][outcome_var].values
for var in candidate_vars:
if var in [target_var, outcome_var]:
continue
var_obs = df[df[target_var].notna()][var].values
if pd.api.types.is_numeric_dtype(df[var]):
target_corr, _ = pearsonr(var_obs, target_obs)
outcome_corr, _ = pearsonr(var_obs, outcome_obs)
else:
continue # 범주는 별도 처리
is_aux = (
abs(target_corr) >= min_target_corr
and abs(outcome_corr) <= max_outcome_corr
)
results.append({
"variable": var,
"target_corr": target_corr,
"outcome_corr": outcome_corr,
"is_auxiliary": is_aux,
})
return pd.DataFrame(results).sort_values("is_auxiliary", ascending=False)
# AirCnC 시뮬레이션
np.random.seed(42)
n = 2000
trait = np.random.normal(0, 1, n) # 미관측 trait
neuro = trait + np.random.normal(0, 0.3, n)
insurance = trait * 30 + np.random.normal(0, 10, n) # trait 강한 영향
active = trait * 0.5 + np.random.normal(0, 0.5, n) # trait 영향
bkg_amt = neuro * (-5) + insurance * 0.5 + np.random.normal(500, 100, n) # bkg 가 진짜 outcome
df = pd.DataFrame({
"neuro": neuro, "insurance": insurance,
"active": active, "bkg_amt": bkg_amt,
})
# Neuro 결측 (50%, MAR)
miss_mask = np.random.uniform(0, 1, n) < 0.5
df.loc[miss_mask, "neuro"] = np.nan
# 보조 변수 식별
aux = identify_auxiliary_variables(
df,
target_var="neuro",
outcome_var="bkg_amt",
candidate_vars=["insurance", "active"],
)
print("=== 보조 변수 후보 ===")
print(aux.to_string(index=False))이 도구가 분석가에게 주는 것:
- 후보 변수 중 보조 조건 만족 자동 점검
- target 과 outcome 과의 상관 매트릭스 한눈에
- 자동 추천 (is_auxiliary 컬럼)
분석가의 결정:
- 추천된 변수 mice 에 추가
- target_corr 너무 작은 변수는 제외 (예: < 0.1)
- outcome_corr 너무 큰 변수는 제외 (mediator 위험)
→ 자동 + 수동 검증의 조합. 효율적.
8.2 2. m 의 첫 시도 결정
def initial_m(df, missing_vars):
"""결측 비율에 기반한 m 의 첫 시도 결정."""
max_miss_pct = max(df[v].isnull().mean() for v in missing_vars)
if max_miss_pct < 0.05:
return 5
elif max_miss_pct < 0.15:
return 10
elif max_miss_pct < 0.30:
return 20
else:
return max(30, int(max_miss_pct * 100))
m_init = initial_m(df, ["neuro"])
print(f"\n초기 m: {m_init}")대부분의 비즈니스 분석에서 m = 10~20 이 충분.
m = 100 은 academic 정확도. 실용적 차이 거의 없음.
→ 시간을 m 에 쓰지 말고 보조 변수 발굴, 도메인 인터뷰 등에 쓰기.
8.3 3. mice + Rubin pooling 통합
from statsmodels.imputation import mice as mi
import statsmodels.api as sm
def integrated_mi_workflow(df, formula, m=20):
"""MICE + Rubin pooling 통합 워크플로."""
# 1. mice
mice_data = mi.MICEData(df)
# 2. m 번 update
for _ in range(m):
mice_data.update_all()
# 3. m 개 데이터셋 생성
imputed_dfs = []
for _ in range(m):
mice_data.update_all()
imputed_dfs.append(mice_data.data.copy())
# 4. 각 데이터셋에 회귀 적합
results = []
for df_imp in imputed_dfs:
# formula 파싱 단순화
Y_col = formula.split("~")[0].strip()
X_cols = [c.strip() for c in formula.split("~")[1].split("+")]
model = sm.OLS(df_imp[Y_col], sm.add_constant(df_imp[X_cols])).fit()
results.append({
"params": model.params,
"bse": model.bse,
})
# 5. Rubin pooling
pooled = {}
for var in results[0]["params"].index:
estimates = [r["params"][var] for r in results]
ses = [r["bse"][var] for r in results]
theta_bar = np.mean(estimates)
U_bar = np.mean(np.array(ses) ** 2)
B = np.var(estimates, ddof=1) if len(estimates) > 1 else 0
T = U_bar + (1 + 1/m) * B
FMI = (1 + 1/m) * B / T if T > 0 else 0
pooled[var] = {
"estimate": theta_bar,
"se": np.sqrt(T),
"FMI": FMI,
}
return pooled
# 적용
pooled = integrated_mi_workflow(df, "bkg_amt ~ neuro + active + insurance", m=20)
print("\n=== Pooled Results ===")
for var, stats in pooled.items():
print(f" {var}: estimate = {stats['estimate']:.3f}, SE = {stats['se']:.3f}, FMI = {stats['FMI']:.3f}")이 함수가 분석가에게 주는 것:
- 데이터 + 분석 식만 입력
- m 번 mice + 회귀 + Rubin pooling 자동
- FMI 까지 출력
분석가의 다음 결정:
- FMI < 0.3 모두: m = 20 충분
- FMI > 0.4 일부: m = 50 재실행
이 통합이 비즈니스 분석 파이프라인의 표준.
9 결측 처리의 종합 결정 트리
1. 결측 비율 < 1% 모두 → drop OK (끝)
2. Sensitivity test (Min/Max) 결과 부호 일치 → drop OK (끝)
3. 본격 처리 진입:
↓
4. 진단:
- Logistic regression of missingness on others
- 도메인 인터뷰
↓
5. 분류:
- MCAR → mice default (PMM, m = 5)
- MAR → mice + 보조 변수 (m = 10~20)
- Probabilistic MNAR → mice + child variables 보조 (m = 20+)
- Deterministic MNAR → 임계값 가정 + truncated sampling + sensitivity
↓
6. 실행 + FMI 점검:
- FMI < 0.3 모두 → 결과 채택
- FMI > 0.4 → m 증가 재실행
↓
7. 보고:
- 진단·도구·m·FMI·가정 명시
- Sensitivity 결과 첨부
이 트리가 결측 처리의 master plan.
10 관련 주제
10.1 Ch.6 의 형제 글 (Ch.6 완결)
- E-BUI6-0 결측 데이터 처리 overview — Ch.6 전체 흐름
- E-BUI6-1 결측 시각화 — 단계 1
- E-BUI6-2 결측 분류와 진단 — 단계 2
- E-BUI6-3 다중 대체 — 단계 3
10.2 후속 챕터
- E-BUI8-0 Theory of Change 실험 설계 overview — Ch.8: 실험 설계
- Phase A-BUI7 — Bootstrap (자세히)
10.3 Hernan 정통 cross-link
- Causal_Inference/08 선택 편향 — Selection bias 와 결측
10.4 카테고리 진입점
- Experimentation 학습 로드맵 — 11 Phase × 7 교재 매핑