1 정의
교란(confounding)은 처리 \(A\)와 결과 \(Y\)의 공통 원인(common cause)이 존재하여 처리–결과 간 연관(association)이 인과 효과(causal effect)와 일치하지 않게 되는 체계적 편향이다.
- DAG에서 \(A\)와 \(Y\) 사이에 뒷문 경로(backdoor path)가 열려 있으면 교란이 존재한다
- 뒷문 경로: \(A\)로 향하는 화살표가 포함된 \(A\)–\(Y\) 비인과 경로
- 교란 = 교환가능성(exchangeability)의 위반: \(Y^{a} \not\!\perp\!\!\!\perp A\)
- 역학: Confounding, Confounding Bias
- IT: Omitted Variable Bias, Confounding / Lurking Variable
| 역학 (Epidemiology) | IT/비즈니스 | 비고 |
|---|---|---|
| Confounding | Omitted Variable Bias | 측정되지 않은 공통 원인에 의한 편향 |
| Confounder | Lurking Variable, Control Variable | 보정에 사용되는 공변량 |
| Backdoor Path | Non-causal Path | DAG에서 처리로 향하는 화살표가 포함된 경로 |
| Backdoor Criterion | — | 뒷문 경로 차단 조건 |
| Exchangeability | Ignorability, Unconfoundedness | \(Y^a \perp\!\!\!\perp A \mid L\) |
| Unmeasured Confounding | Hidden Bias | 측정 불가능한 교란 |
| Signed DAG | — | 편향 방향 예측용 부호화 DAG |
2 개념 및 원리
2.1 교란의 구조
교란의 핵심 구조는 공통 원인이다. DAG에서 \(A\)와 \(Y\)가 공유하는 원인 \(L\) (또는 비측정 \(U\))이 존재하면, \(A \leftarrow L \rightarrow Y\)라는 뒷문 경로가 열린다.
\[ \text{연관 위험비} = \frac{\Pr[Y=1 \mid A=1]}{\Pr[Y=1 \mid A=0]} \;\neq\; \frac{\Pr[Y^{a=1}=1]}{\Pr[Y^{a=0}=1]} = \text{인과 위험비} \]
Hernán & Robins (2020, Ch.7)는 다양한 교란 구조를 제시한다:
| Figure | 구조 | 예시 |
|---|---|---|
| 7.1 | \(A \leftarrow L \rightarrow Y\) | 건강한 근로자 편향 (체력 \(L\) → 소방관 \(A\), 사망 \(Y\)) |
| 7.2 | \(A \leftarrow L \leftarrow U \rightarrow Y\) | 적응증 교란 (아스피린 \(A\) ← 심장병 \(L\) ← 동맥경화 \(U\) → 뇌졸중 \(Y\)) |
| 7.3 | \(A \leftarrow U \rightarrow L \rightarrow Y\) | 생활습관 교란 (운동 \(A\) ← 성격 \(U\) → 흡연 \(L\) → 사망 \(Y\)) |
| 7.4 | 공통 원인 없음 (충돌자 \(L\)) | 교란 없음 — 보정 시 오히려 편향 유발 |
모든 경우에서 편향의 구조는 동일하다: 처리와 결과의 공통 원인이 열린 뒷문 경로를 만든다.
2.2 뒷문 기준 (Backdoor Criterion)
공변량 집합 \(L\)이 뒷문 기준을 만족하려면:
- \(L\)이 \(A\)와 \(Y\) 사이의 모든 뒷문 경로를 차단해야 하고
- \(L\)에 처리 \(A\)의 후손(descendant)이 포함되지 않아야 한다
뒷문 기준 충족 \(\Longleftrightarrow\) 조건부 교환가능성 \(Y^a \perp\!\!\!\perp A \mid L\) (faithfulness 하에서)
뒷문 기준이 충족되는 두 가지 상황:
- 공통 원인 없음 → 뒷문 경로 자체가 없음 → 무조건 교환가능성 → 보정 불필요
- 공통 원인 존재, 측정된 \(L\)로 차단 가능 → 조건부 교환가능성 → \(L\)로 보정
2.3 교란과 교환가능성의 관계
| 상황 | 교환가능성 | 교란 | 보정 |
|---|---|---|---|
| RCT (무조건 무작위 배정) | \(Y^a \perp\!\!\!\perp A\) | 없음 | 불필요 |
| 조건부 무작위 배정 / 관찰 연구 | \(Y^a \perp\!\!\!\perp A \mid L\) | 존재하나 보정 가능 | 표준화 또는 IPW |
| 비측정 공통 원인 존재 | 불성립 | 비측정 교란 | 보정 불가 (민감도 분석) |
2.4 M-편향과 부적절한 보정
Figure 7.4에서 \(L\)은 충돌자(collider)이다:
\[A \leftarrow U_2 \rightarrow L \leftarrow U_1 \rightarrow Y\]
- 보정하지 않으면: 뒷문 경로가 충돌자 \(L\)에서 차단 → 교란 없음
- \(L\)을 보정하면: 충돌자 조건화로 경로가 열려 선택 편향 유발
이 구조를 M-편향(M-bias)이라 부른다 (Greenland, 2003). 변수 \(U_2\), \(L\), \(U_1\)의 구조가 옆으로 누운 ’M’자를 닮았기 때문이다.
전통적 “교란 변수” 정의(연관 기반)에 의존하면 M-편향 구조에서 비교란 변수를 보정하여 편향을 유발할 수 있다. 반드시 DAG에 기반한 구조적 접근으로 보정 변수를 선택해야 한다.
2.5 부호화 DAG와 편향 방향
이분형 변수 \(L\), \(A\), \(Y\)에서 (Hernán & Robins, 2020, Fine Point 7.1):
- \(L \xrightarrow{+} A\), \(L \xrightarrow{+} Y\) (또는 둘 다 \(-\)) → 양의 교란 (효과 과대 추정)
- \(L \xrightarrow{+} A\), \(L \xrightarrow{-} Y\) (또는 반대) → 음의 교란 (효과 과소 추정)
예: 흡연 \(L\)이 심장 이식 \(A\)를 감소(\(-\))시키고, 사망 \(Y\)를 증가(\(+\))시키면 → 음의 교란 → 이식의 보호 효과가 과대 추정됨
2.6 교란 변수 정의: 전통적 vs. 구조적 접근
전통적 정의 (3가지 조건):
- \(L\)은 \(A\)와 연관 (associated)
- \(L\)은 \(A\) 조건 하에서 \(Y\)와 연관
- \(L\)은 \(A \rightarrow Y\) 인과 경로 위에 있지 않음
문제점: Figure 7.4에서 \(L\)은 3가지 조건을 모두 만족하지만 보정하면 편향이 발생한다.
구조적 정의: \(L\)이 교란 변수이려면 \(A\)와 \(Y\) 사이에 구조적 교란이 존재하고, \(A\)와 \(Y\)만으로는 인과 효과를 식별할 수 없으나 \(L\)을 추가하면 식별 가능해야 한다.
구조적 접근은 연구자의 인과 가정(DAG)을 명시적으로 드러내고 비판 가능하게 만든다.
3 직관적 설명
3.1 “천둥과 올려다보기” 비유
Hernán & Robins (2020, Ch.7) 도입 예시:
- 한 보행자(\(A\))가 하늘을 올려다본다
- 다른 보행자(\(Y\))도 올려다본다
- 하지만 천둥 소리(\(L\))가 둘 다 올려다보게 만든 공통 원인일 수 있다
\(A\)와 \(Y\)의 연관이 실제 인과 효과인지, 아니면 공통 원인 \(L\) 때문인지 구분할 수 없다 — 이것이 교란이다.
3.2 IT 비유: “신규 기능과 매출”
- 관찰: 신규 추천 기능(\(A\))을 사용하는 유저의 매출(\(Y\))이 더 높다
- 교란: 파워 유저(\(L\))는 신규 기능을 더 많이 사용하고, 원래 매출도 높다
- 뒷문 경로: 기능 사용 \(\leftarrow\) 파워 유저 \(\rightarrow\) 매출
- 교란 보정 없이: 기능의 효과를 과대 추정 → 잘못된 ROI 보고
A/B 테스트(무작위 배정)는 공통 원인의 영향을 제거하여 교란을 방지한다. 관찰 데이터에서는 파워 유저 여부(\(L\))로 보정해야 한다.
3.3 교란의 역사적 배경
- Yule (1903): 이산 변수에서 교란에 의한 연관을 “허구적(fictitious)”이라 표현
- Pearson et al. (1899): 연속 변수에서 “가짜 상관(spurious correlation)”이라 명명
- Hernán & Robins: 교란에 의한 연관은 실제로 존재하는 연관이다. 다만 인과적으로 해석해서는 안 된다
4 왜 필요한가
교란을 이해하지 못하면 다음과 같은 실무적 실패가 발생한다:
| 상황 | 교란 무시 결과 | 올바른 접근 |
|---|---|---|
| 약물 효과 추정 | 적응증 교란 → 약이 해롭다는 결론 | 질병 중증도로 보정 |
| 기능 효과 측정 | 파워 유저 교란 → 효과 과대 추정 | A/B 테스트 또는 성향 점수 보정 |
| 마케팅 캠페인 | 기존 충성 고객 교란 → ROI 왜곡 | 무작위 홀드아웃 |
| 직업-건강 연관 | 건강한 근로자 편향 → 위험 직업이 안전해 보임 | 선택 편향 + 교란 동시 보정 |
| 유전자-질병 연관 | 인구 층화 교란 → 거짓 유전적 연관 | 인구 구조 보정 (GWAS) |
핵심: 관찰 데이터 분석에서 “연관 ≠ 인과”가 성립하는 가장 흔한 이유가 교란이다. 교란의 구조적 이해는 어떤 변수를 보정해야 하고, 어떤 변수를 보정하면 안 되는지 판단하는 데 필수적이다.
5 응용 분야
| 분야 | 교란의 구체적 형태 | 보정 접근 |
|---|---|---|
| 임상시험 | 적응증 교란 (severity → drug, outcome) | RCT로 제거, 관찰 시 PS 매칭 |
| 테크/추천 시스템 | 사용자 활동 수준 교란 | A/B 테스트, IPW |
| 역학/흡연 연구 | 생활습관 교란 (성격 → 흡연, 운동) | 다변량 보정, DAG 기반 변수 선택 |
| GWAS | 인구 층화 (ethnicity → SNP, trait) | Principal Components 보정 |
| 경제학/노동 | 교육-소득 교란 (능력 → 교육, 소득) | IV (도구 변수), DiD |
| 마케팅 | 기존 충성도 교란 (loyalty → campaign exposure, purchase) | 무작위 홀드아웃, 성향 점수 |
6 예시
6.1 수치 예시: 심장 이식과 사망
Hernán & Robins (2020, Ch.7)의 심장 이식 예시를 수치로 정리한다.
설정: 처리 \(A\) (심장 이식), 결과 \(Y\) (사망), 교란 변수 \(L\) (심장병 중증도)
| \(L = 0\) (경증) | \(L = 1\) (중증) | 전체 | |
|---|---|---|---|
| \(A = 1\) (이식) | 20명 | 80명 | 100명 |
| \(A = 0\) (비이식) | 80명 | 20명 | 100명 |
| \(\Pr[Y=1 \mid A, L]\) | 0.10 | 0.30 | — |
- 주변 연관: \(\Pr[Y=1 \mid A=1] = 0.10 \times 0.2 + 0.30 \times 0.8 = 0.26\)
- 주변 연관: \(\Pr[Y=1 \mid A=0] = 0.10 \times 0.8 + 0.30 \times 0.2 = 0.14\)
- 조정 전 위험비: \(0.26 / 0.14 = 1.86\) → 이식이 해로운 것처럼 보임!
- \(L\)로 표준화: \(\sum_l \Pr[Y=1 \mid A=a, L=l] \Pr[L=l]\)
- \(\Pr[Y^{a=1}=1] = 0.10 \times 0.5 + 0.30 \times 0.5 = 0.20\)
- \(\Pr[Y^{a=0}=1] = 0.10 \times 0.5 + 0.30 \times 0.5 = 0.20\)
- 조정 후 인과 위험비: \(0.20 / 0.20 = 1.0\) → 이식은 효과 없음 (귀무)
교란을 보정하지 않으면 중증 환자가 이식을 더 많이 받고 사망률도 높다는 공통 원인 구조 때문에 이식이 해로워 보인다.
6.2 IT 예시: 프리미엄 구독과 이탈
| 활동 낮음 (\(L=0\)) | 활동 높음 (\(L=1\)) | 전체 | |
|---|---|---|---|
| 프리미엄 (\(A=1\)) | 100명 | 900명 | 1000명 |
| 무료 (\(A=0\)) | 900명 | 100명 | 1000명 |
| 이탈률 (\(Y=1\)) | 0.20 | 0.05 | — |
- 미보정: \(\Pr[Y \mid A=1] = 0.065\), \(\Pr[Y \mid A=0] = 0.185\) → 프리미엄이 이탈을 73% 감소?
- 보정: 동일 활동 수준 내에서 \(A\)와 \(Y\)는 독립 → 프리미엄의 진짜 효과 = 0
- 교란 원인: 활동 수준 \(L\)이 프리미엄 가입(\(A\))과 이탈(\(Y\)) 모두에 영향
7 코드 예시
7.1 교란 시뮬레이션과 보정
import numpy as np
import pandas as pd
from scipy.special import expit
np.random.seed(42)
n = 10_000
# --- DGP: L → A, L → Y (교란 구조 Figure 7.1) ---
L = np.random.binomial(1, 0.5, n) # 교란 변수
A = np.random.binomial(1, expit(-1 + 2 * L), n) # L이 A에 영향
Y = np.random.binomial(1, expit(-2 + 1 * L + 0 * A), n) # A의 진짜 효과 = 0
df = pd.DataFrame({"L": L, "A": A, "Y": Y})
# --- 1. 미보정 연관 ---
naive_rr = df.loc[df.A == 1, "Y"].mean() / df.loc[df.A == 0, "Y"].mean()
print(f"미보정 위험비: {naive_rr:.3f}") # ≈ 1.5 (교란!)
# --- 2. 층화 보정 ---
rr_by_L = {}
for l_val in [0, 1]:
sub = df[df.L == l_val]
rr_by_L[l_val] = sub.loc[sub.A == 1, "Y"].mean() / sub.loc[sub.A == 0, "Y"].mean()
print(f" L={l_val} 보정 위험비: {rr_by_L[l_val]:.3f}") # ≈ 1.0
# --- 3. 표준화 (Standardization) ---
p_L = df["L"].value_counts(normalize=True).sort_index()
risk_std = {}
for a_val in [0, 1]:
risk_a = 0
for l_val in [0, 1]:
sub = df[(df.A == a_val) & (df.L == l_val)]
risk_a += sub["Y"].mean() * p_L[l_val]
risk_std[a_val] = risk_a
causal_rr = risk_std[1] / risk_std[0]
print(f"\n표준화 인과 위험비: {causal_rr:.3f}") # ≈ 1.0
print(f"결론: 미보정 RR={naive_rr:.2f} → 보정 RR={causal_rr:.2f} (교란 제거)")7.2 IPW를 통한 교란 보정
from sklearn.linear_model import LogisticRegression
# --- 성향 점수 추정 ---
ps_model = LogisticRegression()
ps_model.fit(df[["L"]], df["A"])
ps = ps_model.predict_proba(df[["L"]])[:, 1]
# --- IP 가중치 ---
df["w"] = np.where(df.A == 1, 1 / ps, 1 / (1 - ps))
# --- 가중 위험비 ---
ipw_risk = {}
for a_val in [0, 1]:
sub = df[df.A == a_val]
ipw_risk[a_val] = np.average(sub["Y"], weights=sub["w"])
ipw_rr = ipw_risk[1] / ipw_risk[0]
print(f"IPW 인과 위험비: {ipw_rr:.3f}") # ≈ 1.07.3 M-편향 시뮬레이션: 보정이 편향을 유발하는 경우
np.random.seed(123)
n = 50_000
# --- DGP: Figure 7.4 — 공통 원인 없음, L은 충돌자 ---
U1 = np.random.normal(0, 1, n)
U2 = np.random.normal(0, 1, n)
L = (U1 + U2 > 0).astype(int) # L은 U1, U2의 공통 결과 (충돌자)
A = np.random.binomial(1, expit(0.5 * U2), n) # U2 → A
Y = np.random.binomial(1, expit(-1 + 0.5 * U1), n) # U1 → Y, A의 효과 = 0
df_m = pd.DataFrame({"U1": U1, "U2": U2, "L": L, "A": A, "Y": Y})
# --- 미보정 (올바른) ---
naive = df_m.loc[df_m.A == 1, "Y"].mean() - df_m.loc[df_m.A == 0, "Y"].mean()
print(f"미보정 위험차: {naive:.4f}") # ≈ 0 (올바름)
# --- L로 보정 (잘못된) ---
adj_rd = 0
for l_val in [0, 1]:
sub = df_m[df_m.L == l_val]
rd_l = sub.loc[sub.A == 1, "Y"].mean() - sub.loc[sub.A == 0, "Y"].mean()
adj_rd += rd_l * (df_m.L == l_val).mean()
print(f" L={l_val} 위험차: {rd_l:.4f}")
print(f"\nL-보정 위험차: {adj_rd:.4f}") # ≠ 0 (M-편향!)
print("→ 충돌자 L을 보정하면 오히려 편향이 발생한다")7.4 뒷문 기준 판별 함수
def check_backdoor(dag: dict, treatment: str, outcome: str,
adjustment_set: set) -> dict:
"""
간단한 뒷문 기준 판별기.
Parameters
----------
dag : dict
{node: [parents]} 형식의 DAG
treatment, outcome : str
처리와 결과 노드 이름
adjustment_set : set
보정하려는 변수 집합
Returns
-------
dict with 'satisfies_backdoor', 'reason'
"""
# 1. 후손 검사
descendants = set()
def get_desc(node):
for child, parents in dag.items():
if node in parents and child not in descendants:
descendants.add(child)
get_desc(child)
get_desc(treatment)
if adjustment_set & descendants:
return {
"satisfies_backdoor": False,
"reason": f"보정 집합에 처리의 후손 포함: {adjustment_set & descendants}"
}
# 2. (단순) 공통 원인 검사 — 실제로는 d-분리 알고리즘 필요
return {
"satisfies_backdoor": True,
"reason": "후손 조건 통과 (전체 d-분리 검사는 networkx 등 필요)"
}
# 사용 예
dag_fig71 = {"L": [], "A": ["L"], "Y": ["L", "A"]}
print(check_backdoor(dag_fig71, "A", "Y", {"L"}))
# {'satisfies_backdoor': True, ...}8 교란 보정 방법론 분류
Hernán & Robins (2020, Section 7.6)에 따른 교란 보정 방법론:
8.1 G-방법 (Generalized Methods)
조건부 교환가능성 \(Y^a \perp\!\!\!\perp A \mid L\)을 활용하여 전체 모집단의 인과 효과를 추정한다.
| 방법 | 원리 | 교재 |
|---|---|---|
| 표준화 (Standardization) | \(\sum_l \mathrm{E}[Y \mid A=a, L=l] \Pr[L=l]\) | Ch.2, Ch.13 |
| IP 가중치 (IPW) | \(L \rightarrow A\) 화살표를 “삭제”하는 의사-모집단 생성 | Ch.2, Ch.12 |
| G-추정 (G-estimation) | 구조적 중첩 모형에 기반한 추정 | Ch.14 |
8.2 전통적 층화 기반 방법
| 방법 | 원리 | 한계 |
|---|---|---|
| 층화 (Stratification) | \(L\)의 수준 내에서 연관 추정 | 시변 처리에서 선택 편향 유발 가능 |
| 제한 (Restriction) | 분석을 \(L\)의 특정 수준으로 한정 | 일반화 어려움 |
| 매칭 (Matching) | 처리군과 대조군의 \(L\) 분포를 동일하게 | 비측정 교란 보정 불가 |
8.3 교환가능성 불필요 방법
| 방법 | 대안 가정 | 교재 |
|---|---|---|
| 이중 차분 (DiD) | 가산적 동일-교란 | Technical Point 7.3 |
| 도구 변수 (IV) | 배제 제약 | Ch.16 |
| 전문 기준 (Front-door) | 완전 매개 변수 존재 | Technical Point 7.4 |
9 관련 주제
선행 지식
후속 주제
- 선택 편향 — Ch.8 — 충돌자 조건화에 의한 편향
- 측정 오차와 랜덤 변동 — Ch.9-10 — 측정 오류와 표본 변동
- IP 가중치와 주변 구조 모형 — Ch.12 — 교란 보정의 실전적 구현
다른 카테고리 연결
- 관찰 연구와 식별 조건 — Ch.3 — 교환가능성, 양성, 일관성 조건
- 효과 수정과 상호작용 — Ch.4-5 — 하위 그룹별 효과 이질성