교란

Confounding — 공통 원인이 만드는 허위 연관의 구조와 보정

교란(confounding)의 DAG 기반 구조적 정의, 뒷문 경로(backdoor path)와 뒷문 기준(backdoor criterion), 교환가능성과의 관계, 교란 변수(confounder)의 정의 문제, M-편향, 부호화 DAG를 통한 편향 방향 예측, 그리고 교란 보정 방법론을 다룬다. Hernán & Robins (2020) Ch.7을 기반으로 작성하였다.

Experimentation
Causal Inference
저자

Kwangmin Kim

공개

2026년 03월 20일

1 정의

정의: 교란 (Confounding)

교란(confounding)은 처리 \(A\)와 결과 \(Y\)공통 원인(common cause)이 존재하여 처리–결과 간 연관(association)이 인과 효과(causal effect)와 일치하지 않게 되는 체계적 편향이다.

  1. DAG에서 \(A\)\(Y\) 사이에 뒷문 경로(backdoor path)가 열려 있으면 교란이 존재한다
  2. 뒷문 경로: \(A\)로 향하는 화살표가 포함된 \(A\)\(Y\) 비인과 경로
  3. 교란 = 교환가능성(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)

뒷문 기준 (Pearl, 1995)

공변량 집합 \(L\)이 뒷문 기준을 만족하려면:

  1. \(L\)\(A\)\(Y\) 사이의 모든 뒷문 경로를 차단해야 하고
  2. \(L\)에 처리 \(A\)후손(descendant)이 포함되지 않아야 한다

뒷문 기준 충족 \(\Longleftrightarrow\) 조건부 교환가능성 \(Y^a \perp\!\!\!\perp A \mid L\) (faithfulness 하에서)

뒷문 기준이 충족되는 두 가지 상황:

  1. 공통 원인 없음 → 뒷문 경로 자체가 없음 → 무조건 교환가능성 → 보정 불필요
  2. 공통 원인 존재, 측정된 \(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가지 조건):

  1. \(L\)\(A\)와 연관 (associated)
  2. \(L\)\(A\) 조건 하에서 \(Y\)와 연관
  3. \(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) 도입 예시:

  1. 한 보행자(\(A\))가 하늘을 올려다본다
  2. 다른 보행자(\(Y\))도 올려다본다
  3. 하지만 천둥 소리(\(L\))가 둘 다 올려다보게 만든 공통 원인일 수 있다

\(A\)\(Y\)의 연관이 실제 인과 효과인지, 아니면 공통 원인 \(L\) 때문인지 구분할 수 없다 — 이것이 교란이다.

3.2 IT 비유: “신규 기능과 매출”

  1. 관찰: 신규 추천 기능(\(A\))을 사용하는 유저의 매출(\(Y\))이 더 높다
  2. 교란: 파워 유저(\(L\))는 신규 기능을 더 많이 사용하고, 원래 매출도 높다
  3. 뒷문 경로: 기능 사용 \(\leftarrow\) 파워 유저 \(\rightarrow\) 매출
  4. 교란 보정 없이: 기능의 효과를 과대 추정 → 잘못된 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.0

7.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 관련 주제

선행 지식

후속 주제

다른 카테고리 연결

Subscribe

Enjoy this blog? Get notified of new posts by email: