1 결측 처리
1.1 MCAR vs MAR vs MNAR (재방문)
| 메커니즘 | 정의 | 처리 |
|---|---|---|
| MCAR (Completely At Random) | 결측이 데이터 전혀 무관 | listwise OK |
| MAR (At Random) | 결측이 관측 변수에만 의존 | imputation, mixed model |
| MNAR (Not At Random) | 결측이 결측값 자체에 의존 | 매우 어려움 (sensitivity analysis) |
농학·산업의 결측은 흔히 MCAR (자연재해, 기계 고장). 임상은 MAR 가능 (drop-out 이 상태에 의존).
1.2 Single Missing — Yates 의 보정 (재방문)
G-MON2-3 의 절차. 한 셀 결측 시 추정값으로 대체 후 자유도 -1 보정.
1.3 Multiple Missing — Multiple Imputation
여러 셀 결측 시:
- Multiple Imputation (MI): 결측 셀에 여러 (예: 5) plausible 값을 stochastic 으로 생성.
- 각 imputed 데이터셋에서 분석.
- Rubin’s rules 로 결과 결합.
R mice, Python sklearn.impute.IterativeImputer.
1.4 Mixed Model 의 자동 처리
Multilevel/mixed model 은 결측을 likelihood-based 로 자동 처리 (MAR 가정).
2 변환 (Transformation)
2.1 변환의 동기
ANOVA 가정: 1. 정규성: 잔차 정규. 2. 등분산성: 모든 그룹 같은 분산. 3. 독립성: 잔차 독립. 4. 선형성 (ANCOVA): covariate 효과 선형.
위반 시 변환 검토.
2.2 표준 변환
| 응답 종류 | 분산 ~ 평균 | 변환 |
|---|---|---|
| Counts (Poisson) | \(\sigma^2 \propto \mu\) | \(\sqrt{Y}\) 또는 \(\sqrt{Y + 0.5}\) |
| 분율 (Binomial) | \(\sigma^2 \propto p(1-p)\) | \(\arcsin\sqrt{Y/n}\) |
| Skewed positive | \(\sigma^2 \propto \mu^2\) | \(\log Y\) 또는 \(\log(Y+1)\) |
| Heavy tail | \(\sigma^2 \propto \mu^3\) | \(1/Y\) |
2.3 Box-Cox 변환 (재방문)
\[ Y^{(\lambda)} = \begin{cases} (Y^\lambda - 1)/\lambda & \lambda \ne 0 \\ \log Y & \lambda = 0 \end{cases} \]
\(\lambda\) 의 maximum likelihood 추정.
2.4 잔차 분석 — 변환 선택
- Residual vs fitted plot: 패턴 (funnel, curve) → heteroscedastic.
- Q-Q plot: 정규성 점검.
- Levene test: 등분산성 정량 검정.
- Box-Cox profile: \(\lambda\) 의 likelihood 곡선.
3 가설 사례 — 농학 수확량 (Lognormal)
3.1 데이터
3 비료 × 8 plot. 수확량 (\(Y\)) 이 lognormal 분포.
| 비료 | \(\bar Y\) | \(s_Y\) |
|---|---|---|
| A | 50 | 15 |
| B | 80 | 24 |
| C | 120 | 36 |
분산이 평균과 비례 (CV ≈ 30% 일정) → lognormal 신호.
3.2 Box-Cox 분석
Profile likelihood 의 \(\hat\lambda \approx 0\) → log transform.
3.3 변환 후 ANOVA
| Source | \(SS\) | \(F\) |
|---|---|---|
| 비료 (raw \(Y\)) | 30000 | 8.0 (등분산 X) |
| 비료 (log \(Y\)) | 5.5 | 25.0 (등분산 OK) |
검정력 ↑ 변환 후.
4 Python 코드
import numpy as np
import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols
from scipy import stats
from scipy.stats import boxcox
import matplotlib.pyplot as plt
np.random.seed(2026)
treatments = ["A", "B", "C"]
true_means = {"A": 50, "B": 80, "C": 120}
n = 12
records = []
for t in treatments:
mu = true_means[t]
log_mu = np.log(mu)
Y = np.random.lognormal(log_mu, 0.3, n)
for y in Y:
records.append({"treatment": t, "Y": y})
data = pd.DataFrame(records)
# 1) 잔차 분석 — variance vs mean
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# (a) Boxplot
data.boxplot(column="Y", by="treatment", ax=axes[0])
axes[0].set_title("Y by treatment (heteroscedastic)")
# (b) Variance vs mean
group_var = data.groupby("treatment")["Y"].var()
group_mean = data.groupby("treatment")["Y"].mean()
axes[1].scatter(group_mean, group_var)
axes[1].set_xlabel("Group mean")
axes[1].set_ylabel("Group variance")
axes[1].set_title("Variance ∝ Mean²?")
# (c) After log transform
data["log_Y"] = np.log(data["Y"])
group_var_log = data.groupby("treatment")["log_Y"].var()
group_mean_log = data.groupby("treatment")["log_Y"].mean()
axes[2].scatter(group_mean_log, group_var_log)
axes[2].set_xlabel("Group mean (log Y)")
axes[2].set_ylabel("Group variance (log Y)")
axes[2].set_title("After log: Variance constant?")
plt.tight_layout()
# 2) Box-Cox lambda
Y_bc, lambda_hat = boxcox(data["Y"])
print(f"Estimated Box-Cox lambda = {lambda_hat:.3f}")
# CI for lambda (profile likelihood)
# scipy.stats.boxcox_normplot 활용 가능
# 3) ANOVA before vs after transform
print("\n=== ANOVA on raw Y ===")
model_raw = ols("Y ~ C(treatment)", data=data).fit()
print(sm.stats.anova_lm(model_raw).round(3))
print("\n=== ANOVA on log(Y) ===")
model_log = ols("log_Y ~ C(treatment)", data=data).fit()
print(sm.stats.anova_lm(model_log).round(3))
# 4) Levene's test (등분산)
groups_raw = [data[data["treatment"] == t]["Y"].values for t in treatments]
groups_log = [data[data["treatment"] == t]["log_Y"].values for t in treatments]
W_raw, p_raw = stats.levene(*groups_raw)
W_log, p_log = stats.levene(*groups_log)
print(f"\nLevene test (raw): W = {W_raw:.3f}, p = {p_raw:.4f}")
print(f"Levene test (log): W = {W_log:.3f}, p = {p_log:.4f}")5 변환의 trade-off
5.1 장점
- ANOVA 가정 만족.
- 잔차 분포 정상화.
- 변환 후 \(F\) 검정 정확.
5.2 단점
- 해석 어려움: 변환된 척도에서의 차이를 원래 척도로 어떻게?
- 외삽 위험: 변환 함수의 비선형성으로 외삽 신뢰 ↓.
- 모형 보고: 두 척도 모두 보고 (raw + transformed).
5.3 대안 — GLM
Generalized Linear Model 은 변환 없이 비-정규 응답 모형화 가능:
| 응답 | GLM | 변환 대안 |
|---|---|---|
| Poisson counts | Poisson regression | \(\sqrt{Y}\) |
| Binomial 분율 | Logistic | arcsin |
| Lognormal | Gamma | \(\log Y\) |
GLM 은 응답을 변환하지 않고 link function 을 통해 모형. 해석은 원래 척도에서.
변환: 응답 자체를 바꿈. 변환 후 정규 + 등분산 만족 → 표준 ANOVA.
GLM: 응답은 그대로, link function 으로 평균을 변환 (\(\log E[Y] = \mathbf{x}^T \boldsymbol{\beta}\)). 분포 가정은 응답에 직접.
GLM 이 현대 표준 (R glm, Python statsmodels.GLM). 그러나 정통 DOE 의 변환 도구는 다음 이유로 여전히 유용: - ANOVA 표가 익숙. - 작은 표본에서 GLM 추정 불안정. - 도메인 지식 (예: 약리학의 log dose) 으로 변환이 자연스러움.
6 MON Ch.8 시리즈 정리
G-MON8-0 ANCOVA · Transformation 개관
G-MON8-1 ANCOVA + RBD
G-MON8-2 CRD/Latin/비직교 Two-Way
G-MON8-3 비직교 + Multi-Covariate
G-MON8-4 결측 + 변환 ← 현재 글 (마지막)
↓
G-MON9 (Weighing Designs)
7 가정과 한계
- 결측 메커니즘 가정 (MCAR/MAR): 진단 어려움.
- 변환의 해석 어려움: 두 척도 모두 보고.
- GLM 대안 우위: 작은 표본·복잡 분포에서.
- 잔차 분석의 중요성: 변환 선택의 근거.
8 관련 주제
선행 지식
후속 주제
- G-MON9 — Weighing Designs (작성 예정)
다른 카테고리 연결
- Statistics — GLM 통합 — 변환의 GLM 대안
- Statistics — LDA Missing Data — 결측 처리 정통
9 더 읽을 거리
- Box, G. E. P., Cox, D. R. (1964). “An analysis of transformations.” JRSS Series B 26(2): 211-252 — Box-Cox 원조 논문.
- Atkinson, A. C. (1985). “Plots, Transformations, and Regression.” Oxford University Press.
- Carroll, R. J., Ruppert, D. (1988). “Transformation and Weighting in Regression.” Chapman & Hall.
- McCullagh, P., Nelder, J. A. (1989). “Generalized Linear Models” (2nd ed). Chapman & Hall — GLM 의 표준 reference.
- Little, R. J. A., Rubin, D. B. (2019). “Statistical Analysis with Missing Data” (3rd ed). Wiley.