백도어 기준과 M-패턴 — 정밀한 confounder 식별의 두 얼굴 (Buisson Ch.5.2)

Backdoor Criterion 의 최소성과 Smoking-Seatbelt 의 실제 토바코 소송 함정

Buisson (2021) Ch.5 의 두 번째 변수 선택 규칙인 Backdoor Criterion (BC) 을 자세히 정리한다. Path·causal vs noncausal·blocked 의 정의, BC 의 절차, M-pattern (fork -collider-fork 구조) 의 함정, 2006 년 토바코 소송의 안전벨트-흡연 사례, BC vs DCC 의 trade-off 를 시뮬레이션으로 시연한다.

Experimentation
Causal Inference
저자

Kwangmin Kim

공개

2026년 05월 08일

1 정의

정의: Backdoor Criterion (BC)

\(T\)\(Y\) 사이의 인과 관계는, \(T\) 로 들어오는 화살표로 시작하는 차단되지 않은 noncausal path 가 적어도 하나 있으면 confounded 다. 모든 confounding 을 제거하려면, 이러한 모든 path 를 차단해야 한다.”

(Buisson, 2021, Ch.5; Pearl, 2009)

수식 표기:

\[ \text{BC : 모든 backdoor path 가 controlled 변수 집합 } \mathbf{Z} \text{ 로 차단됨} \]

여기서 backdoor path = \(T\) 로 들어오는 화살표 (\(\to T\)) 로 시작하는 noncausal path.

직관 — “Backdoor” 의 의미

“Backdoor” = “뒷문”.

T (cause of interest) ──→ Y (effect of interest)   ← Front door
      ↑
      │ (← arrows into T)
   Confounder                                       ← Back door
      │
      → Y

Confounder 는 T 의 뒷문 으로 들어와 Y 에 도달하는 비-인과 경로를 만든다.

BC 는 이 뒷문들을 막는 도구. 앞문 (causal path) 은 그대로 두면서 뒷문만 차단.

→ DCC 의 “모든 cause 통제” 보다 정밀. 뒷문만 막음.

2 개념 및 원리 — BC 의 전제 정의

2.1 Path 의 분류

Path · Causal · Noncausal

E-BUI3-3 에서 도입한 정의 재방문:

  • Path: 두 변수 사이 화살표로 연결된 sequence (방향 무관, 변수 중복 없음)
  • Causal Path: 모든 화살표가 같은 방향 (chain). \(T\) 의 영향이 \(Y\) 로 전달되는 경로.
  • Noncausal Path: 적어도 하나의 fork 또는 collider 포함.

C-Mart 사례에서 NumberOfCustomers 와 BottledWaterSales 사이 path 7 개:

  1. NumberOfCustomers → IceCreamSales → BottledWaterSales (causal — chain)
  2. NumberOfCustomers → BurgerSales → FrenchFrySales → BottledWaterSales (causal — chain)
  3. NumberOfCustomers → BurgerSales → FrenchFrySales ← Mindset → BottledWaterSales (noncausal — fork at FrenchFry… 잠깐, FrenchFry 가 collider here. noncausal due to collider)
  4. (이하 5개 더, 모두 collider 또는 fork 포함 → noncausal)

→ 7 path 중 2 개만 causal. 나머지 5 개는 noncausal — 통제 결정 시 점검 대상.

직관 — Causal vs Noncausal 의 의미

Causal path: \(T\)\(Y\)인과적 영향 을 주는 경로. 이 경로의 효과는 \(T\) 의 진짜 효과의 일부이므로 차단하면 안 됨.

Noncausal path: \(T\)\(Y\) 사이 상관을 만들지만 인과 아님 의 경로. 이 경로의 효과는 confounding bias 이므로 차단해야 함.

→ BC 의 핵심: causal path 는 보존, noncausal path 만 차단.

DCC 의 “mediator 제외” 가 같은 의미 — chain 의 mediator 통제는 causal path 차단이므로 금지.

2.2 Blocked vs Unblocked Path

차단 규칙 (재정리)

Path 가 blocked (차단됨) 인 조건:

    1. Path 위의 비-collider 변수가 회귀에 통제됨, OR
    1. Path 위의 collider 가 회귀에 통제되지 않음 (그리고 그 collider 의 후손도 통제되지 않음)

Path 가 unblocked (차단되지 않음) 인 조건:

    1. Path 위에 통제된 비-collider 변수가 없음, AND
    1. Path 위의 모든 collider 가 통제됨 (또는 그 후손이 통제됨)

→ Collider 와 비-collider 의 통제 효과가 정반대.

직관 — 정보 흐름의 “댐” 비유

Path = 강. 변수의 통제 = 댐.

비-collider 의 통제: 강에 댐을 세움 → 정보 흐름 차단. Collider 의 통제: 본래 막혀 있던 지하 통로를 뚫음 → 정보 흐름 개방.

[비-collider 통제]
   T ── A ── Y
        ↓ (통제)
   T ── [A] ── Y       ← 차단됨

[Collider 통제]
   T ── C ── Y
   (양쪽 화살표가 C 로)
        ↓ (통제)
   T ←── C ──→ Y      ← 새 경로 개방

→ 변수의 역할 (collider vs 비-collider) 에 따라 통제 효과가 정반대. CD 가 정확해야 결정.

2.3 BC 의 알고리즘

5 단계 절차
1. T 로 들어오는 화살표 모두 식별 (T 의 직접 원인)
2. 각 직접 원인에서 시작하는 path 모두 열거 (T 부터 Y 까지)
3. 각 path 가 causal 인지 noncausal 인지 분류
4. Noncausal path 가 자연스럽게 차단되었는지 점검:
   - Path 위에 collider 가 있으면서 그 collider 가 통제 안 되면 → 자연 차단
   - 그 외에는 unblocked → 통제 변수 추가 필요
5. Unblocked noncausal path 를 차단하는 최소 통제 변수 집합 찾기

→ 알고리즘적이지만 손으로는 시간 걸림. dowhy 같은 라이브러리 사용 권장.

3 C-Mart 사례 — BC 적용 자세히

3.1 Block 1 — BC

IceCreamSales → BottledWaterSales 의 backdoor

CD:

NumberOfCustomers ──→ IceCreamSales ──→ BottledWaterSales
                ──→ BurgerSales ──→ FrenchFrySales ──→ BottledWaterSales

Backdoor (T 로 들어오는 화살표): NumberOfCustomers → IceCreamSales

이 path 를 따라가는 backdoor:

IceCreamSales ← NumberOfCustomers → BurgerSales → FrenchFrySales → BottledWaterSales

분류:

  • noncausal? Yes (NumberOfCustomers 에서 fork)
  • 자연 차단? No (collider 없음, 통제 안 함)
  • → unblocked → 통제 필요

차단 방법: path 위 비-collider (NumberOfCustomers, BurgerSales, FrenchFrySales) 중 하나 통제.

Buisson 의 권장: T 의 직접 원인 (NumberOfCustomers) 우선.

이유: 이 변수가 다른 backdoor path 에도 동시에 존재할 가능성이 높음 → 한 변수로 여러 path 차단.

직관 — “T 의 직접 원인” 우선의 효율

NumberOfCustomers 통제 시:

  • Path 1 차단 (위에서 시연)
  • 다른 path (NumberOfCustomers 가 시작인 모든 path) 도 자동 차단
  • “직접 원인” 한 개로 그 변수의 모든 영향을 회귀에 흡수

만약 BurgerSales 또는 FrenchFrySales 만 통제하면:

  • Path 1 은 차단되지만
  • NumberOfCustomers 의 다른 backdoor (있다면) 는 미처리
  • 분석가가 각 path 일일이 점검해야

→ “T 의 직접 원인 우선” 이 분석 작업을 줄임.

3.2 Block 2 — BC

AverageCustomerAge 와 HealthMindset 의 path

CD:

   AverageCustomerAge ──→ IceCreamSales
                      ──→ SodaSales (collider)
   CustomerHealthMindset ──→ BottledWaterSales
                         ──→ SodaSales (collider)
                         ──→ FrenchFrySales (collider, Block 1 과 결합)

Backdoor path:

IceCreamSales ← AverageCustomerAge → SodaSales ← CustomerHealthMindset → BottledWaterSales

분류:

  • noncausal? Yes (AverageAge 에서 fork, SodaSales 에서 collider, HealthMindset 에서 fork)
  • 자연 차단? Yes (SodaSales 가 collider, 통제 안 함 → 자동 차단)
  • → blocked → 통제 불필요

→ Block 2 의 미관측 변수 (AverageAge, HealthMindset) 가 회귀에 없어도 OK. SodaSales 의 collider 가 path 를 자연스럽게 막음.

→ DCC 와 결정적 차이. DCC 는 두 미관측 변수의 부재로 적용 불가하지만, BC 는 collider 자연 차단으로 우회.

SodaSales 통제 절대 금지

만약 분석가가 “SodaSales 도 추가하면 좋지 않을까” 라고 통제하면:

  • Collider 가 통제됨 → path 가 unblocked 됨
  • 가짜 confounding 발생
  • IceCreamSales → BottledWaterSales 추정 편향

→ Collider 식별 + 회피가 BC 의 핵심.

4 M-Pattern — Forks-Collider-Forks 구조

4.1 정의

M 모양

Block 2 의 path 를 시각화:

  AverageAge          HealthMindset
        ╲             ╱
         ╲           ╱
   IceCream      BottledWater
                ↘
              SodaSales
              (collider)

또는 재배열:

AverageAge       HealthMindset
   │                  │
   │                  │
   └──→ SodaSales ←──┘     (collider)
   │                  │
   ↓                  ↓
IceCreamSales    BottledWaterSales

이 모양이 알파벳 “M” 을 닮음 → M-pattern.

직관 — M-pattern 이 함정인 이유

분석가의 자연스러운 직감: “SodaSales 가 IceCream 과 BottledWater 와 상관이 있으니 confounder 같다. 통제하자.”

함정:

  • SodaSales 는 “confounder 처럼 보이지만” 사실 collider
  • 통제하면 가짜 confounding 발생

이 함정은 흔함. M-pattern 의 시각적 인식 + collider 식별 능력이 분석가의 무기.

→ CD 를 그릴 때 M 모양이 보이면 “조심” 신호.

4.2 실제 사례 — Smoking · Seatbelt · Lung Cancer

2006 년 토바코 소송

The Book of Why (Pearl & Mackenzie, 2018) 에서 인용된 실제 사례.

토바코 회사가 안전벨트 사용 통계를 사용해 흡연의 폐암 효과를 축소 추정하려 했다.

그들의 회귀 모형:

\[ \text{LungCancer} = \beta_S \cdot \text{Smoking} + \beta_B \cdot \text{SeatbeltUse} + \cdots \]

근거:

  • “안전벨트 사용은 건강 의식의 indicator. 통제하면 건강 행동 보정 가능.”
  • “회귀에 더 많은 변수 = 더 정확한 추정.”

결과: \(\beta_S\) 가 의도적으로 작게 나타남. 흡연의 효과가 축소되어 보임.

문제: 안전벨트 사용은 collider 였다.

진짜 CD
HealthConsciousness   RiskTolerance
        │                  │
        │                  │
        └──→ SeatbeltUse ←─┘     (collider!)
        │                  │
        ↓                  ↓
     LungCancer         Smoking
  • HealthConsciousness 가 강하면 안전벨트 ↑, 폐암 ↓ (운동·식이)
  • RiskTolerance 가 강하면 안전벨트 ↓, 흡연 ↑

SeatbeltUse 가 두 trait 의 collider. 통제하면 두 trait 사이 가짜 음의 상관 → Smoking 과 LungCancer 사이 가짜 음의 상관 (collider bias).

→ “통제 변수를 더 추가하면 더 정확” 의 단순 직감이 통계학적으로 잘못됨을 보여주는 고전 사례.

직관 — 비즈니스 분석에서의 교훈

이 사례는 학술 논쟁뿐 아니라 비즈니스에 직접 적용:

  • 고객 분석: 회원 등급은 collider 가 될 수 있음 (구매 + 활동의 결과)
  • HR 분석: 승진은 collider (성과 + 사내 정치)
  • 의료 데이터: 입원은 collider (병1 + 병2)

이런 collider 변수를 회귀에 추가하면 가짜 상관 발생.

→ 분석가가 항상 자문: “이 변수가 collider 인가?”

5 CD 의 부정확성에 대한 BC 의 취약성

CD 가 틀리면 BC 도 틀린다

만약 마케팅 팀이 CD 를 잘못 그렸다면:

실제: HealthMindset ──→ SodaSales
잘못: SodaSales ──→ HealthMindset

이 한 화살표 방향 오류가 SodaSales 의 역할을 collider 에서 mediator 로 바꿈.

BC 적용 결과:

  • 잘못된 CD 에서: SodaSales 가 mediator 로 보이므로 통제하면 path 차단된다고 잘못 판단
  • 실제로는: SodaSales 가 collider 이므로 통제하면 path 가 개방됨

→ 분석가가 CD 의 정확성을 점검하지 않으면 BC 는 잘못된 처방을 줌.

DCC 였다면? “Cause of T or Y” 모두 통제 — 화살표 방향에 덜 민감 (SodaSales 가 cause of T 또는 Y 가 아니므로 어느 방향이든 통제 안 함).

직관 — DCC vs BC 의 안전성 균형
CD 정확성 DCC BC
완전 정확 작동 (over-control) 작동 (효율적)
화살표 방향 일부 오류 작동 (robust) 잘못 작동 가능
변수 일부 누락 부분 작동 부분 작동
Mediator 잘못 식별 잘못 작동 (over-adjustment) 잘못 작동

→ DCC 는 “구조적 오류” 에 robust, BC 는 “구조적 오류” 에 fragile.

분석가의 선택: CD 가 잘 검증되었으면 BC, 아니면 DCC. 두 결과를 비교하면 더 안전.

6 응용 — BC 의 다양한 사례

6.1 SaaS Onboarding

BC 적용

CD:

PastExp  JobRole       Cohort  SignupChannel
   ↓        ↓            ↓          ↓
   └────→ Tutorial ──→ Retention
   └────────────────────↗ (PastExp 도 직접)
   └────────────────────↗
                          (Cohort 는 Tutorial 과 무관, Retention 만 영향 가정)

T = Tutorial, Y = Retention.

Tutorial 의 직접 원인: PastExp, JobRole, SignupChannel. Retention 의 직접 원인: Tutorial, PastExp, JobRole, Cohort, SignupChannel.

Backdoor path:

  • Tutorial ← PastExp → Retention (noncausal, fork) → 통제 필요
  • Tutorial ← JobRole → Retention (noncausal, fork) → 통제 필요
  • Tutorial ← SignupChannel → Retention (noncausal, fork) → 통제 필요

Cohort 는 Tutorial 의 원인 아니므로 backdoor 가 아님 → BC 통제 불필요.

DCC 라면 Cohort 도 통제. BC 가 더 정밀 — Cohort 는 Y 만 영향이므로 confounder 아님.

6.2 E-commerce 추천

BC 적용

CD:

PastFrequency  SearchIntent      ConversionContext
       ↓             ↓                  ↓
       └──→ Recommendation ──→ Purchase
       └──→ ────────────────↗
       └──→ ────────────────↗
                              (ConversionContext 만 Purchase, Recommendation 무관)

Backdoor: Recommendation ← PastFrequency → Purchase, Recommendation ← SearchIntent → Purchase.

→ PastFrequency, SearchIntent 통제. ConversionContext 는 BC 통제 불필요.

7 코드 예시 — BC 자동 식별 + 시뮬레이션

7.1 BC 자동 식별 (dowhy 활용)

from dowhy import CausalModel
import pandas as pd
import numpy as np

# 가상 C-Mart 데이터 생성
np.random.seed(42)
n = 5000

# 미관측 변수
age = np.random.normal(35, 10, n)
mindset = np.random.normal(0, 1, n)

# 관측 변수
n_customers = np.random.normal(100, 30, n)
ice_cream = 0.3 * n_customers + 0.05 * (45 - age) + np.random.normal(0, 5, n)
burger = 0.5 * n_customers + np.random.normal(0, 5, n)
fries = 0.6 * burger + 0.2 * mindset + np.random.normal(0, 5, n)
soda = 0.2 * n_customers + 0.05 * (45 - age) + 0.2 * mindset + np.random.normal(0, 5, n)
water = (
    0.0 * ice_cream  # 진짜 인과 효과 = 0
    + 0.4 * fries
    + 0.5 * mindset
    + np.random.normal(0, 5, n)
)

df = pd.DataFrame({
    "ice_cream": ice_cream, "water": water,
    "n_customers": n_customers, "burger": burger,
    "fries": fries, "soda": soda,
})

# CausalModel — CD 를 GraphViz 표기로
graph_dot = """
digraph {
    n_customers -> ice_cream;
    n_customers -> burger;
    burger -> fries;
    fries -> water;
    n_customers -> soda;
    ice_cream -> water;
}
"""

model = CausalModel(
    data=df,
    treatment="ice_cream",
    outcome="water",
    graph=graph_dot,
)

# Identify effect (BC 자동 적용)
identified = model.identify_effect()
print("=== BC 의 식별 결과 ===")
print(identified)

# Backdoor variables 확인
print(f"\nBackdoor 변수: {identified.get_backdoor_variables()}")
직관 — dowhy 가 자동으로 처리하는 것

dowhy 는:

  1. CD 를 입력받음
  2. 모든 path 자동 열거
  3. Backdoor path 식별
  4. Collider 식별 + 자연 차단 점검
  5. 최소 통제 변수 집합 반환

분석가의 작업: CD 입력 + 결과 검토.

→ 비즈니스 분석 파이프라인에 표준화.

7.2 M-pattern 시뮬레이션

import statsmodels.api as sm

# M-pattern: Age, Mindset → SodaSales (collider)
np.random.seed(42)
n = 5000

age = np.random.normal(0, 1, n)
mindset = np.random.normal(0, 1, n)

# Soda 는 collider
soda = 0.5 * age + 0.5 * mindset + np.random.normal(0, 0.5, n)

# IceCream, Water 는 각각 한쪽 trait 만 의존 (직접 인과 0)
ice_cream = 0.7 * age + np.random.normal(0, 0.5, n)
water = 0.7 * mindset + np.random.normal(0, 0.5, n)

# 진짜 IceCream → Water 인과 효과 = 0

df_m = pd.DataFrame({
    "ice_cream": ice_cream, "water": water,
    "age": age, "mindset": mindset, "soda": soda,
})

# 회귀 1: 단순
m1 = sm.OLS(df_m["water"], sm.add_constant(df_m["ice_cream"])).fit()
print(f"=== 단순: water ~ ice_cream ===")
print(f"  beta = {m1.params['ice_cream']:.3f} (진짜 0)")

# 회귀 2: BC 적용 (collider soda 통제 안 함, age, mindset 미관측 가정)
print(f"\n=== BC: 통제 변수 없음 (collider 자연 차단) ===")
print(f"  beta = {m1.params['ice_cream']:.3f}")
print(f"  → BC 가 collider 자연 차단 활용해 미관측 변수 통제 불필요")

# 회귀 3: 잘못된 통제 (soda 추가)
m3 = sm.OLS(df_m["water"], sm.add_constant(df_m[["ice_cream", "soda"]])).fit()
print(f"\n=== 잘못: water ~ ice_cream + soda ===")
print(f"  beta = {m3.params['ice_cream']:.3f}  ← collider bias!")
직관 — Collider Bias 의 시각화

예상 결과:

  • 단순 (BC 처방): \(\beta \approx 0\) (정확, collider 자연 차단)
  • Soda 추가: \(\beta \approx -0.3\) (가짜 음의 상관 — collider bias)

같은 데이터, 같은 진짜 효과 (0), 그러나 통제 변수 선택에 따라 0 vs -0.3.

→ Collider 통제는 “분석을 망치는 가장 빠른 방법”. BC 가 이를 회피하는 도구.

7.3 DCC vs BC 비교 시뮬레이션

# 같은 시나리오에서 DCC vs BC
print("\n=== DCC vs BC 비교 ===")

# 미관측 변수 처리: 시뮬레이션에서는 관측되었다고 가정 (현실에서는 불가)
df_full = df_m.copy()  # age, mindset 모두 관측

# DCC: cause of T (age) + cause of Y (mindset) 통제
m_dcc = sm.OLS(df_full["water"], sm.add_constant(df_full[["ice_cream", "age", "mindset"]])).fit()
print(f"\nDCC: water ~ ice_cream + age + mindset")
print(f"  beta = {m_dcc.params['ice_cream']:.3f}, SE = {m_dcc.bse['ice_cream']:.3f}")

# BC: 통제 변수 없음 (collider 자연 차단)
m_bc = sm.OLS(df_full["water"], sm.add_constant(df_full["ice_cream"])).fit()
print(f"\nBC: water ~ ice_cream (only)")
print(f"  beta = {m_bc.params['ice_cream']:.3f}, SE = {m_bc.bse['ice_cream']:.3f}")

print("\n→ DCC, BC 모두 정확한 추정. 단 BC 가 변수 더 적음.")
print("→ 미관측 시나리오 (age, mindset 관측 불가): BC 만 적용 가능.")
직관 — BC 의 우월성 (collider 가 있을 때)

이 시나리오에서:

  • DCC 는 age, mindset 의 데이터 필요
  • BC 는 collider (soda) 의 자연 차단 활용해 미관측 변수 우회

미관측 변수가 있는 현실에서 BC 가 결정적 우위.

그러나 BC 의 비용: CD 가 정확해야 함. CD 가 틀리면 BC 가 잘못된 결과.

→ CD 검증 + BC 적용. CD 검증 부족하면 DCC 로 안전 확보.

8 Conclusion — DCC vs BC 종합

두 규칙의 균형

DCC 와 BC 는 동일한 목적 (confounding 제거) 의 다른 도구.

상황 권장
CD 가 잘 검증됨, 변수 모두 관측 BC (효율적)
CD 가 부분 부정확, 일부 변수 미관측 DCC (안전)
Collider 의 자연 차단 활용 가능 BC (BC 만 가능)
분석가가 CD 에 자신 없음 DCC (robust)
두 결과 비교하고 싶음 둘 다 적용 (대조)

→ 두 규칙을 alternative tool 로 사용. 한 규칙만 고집 안 함.

직관 — 분석가의 default

추천 default:

  1. CD 짓기 + 검증 (E-BUI4)
  2. DCC + BC 둘 다 적용 — 두 결과 비교
  3. 일치하면 결과 신뢰
  4. 불일치하면 CD 재검토 (특히 collider 식별)

이 default 가 분석의 안전성과 정밀성을 동시에 확보.

9 관련 주제

9.1 Ch.5 의 형제 글 (Ch.5 완결)

9.2 이전 챕터

9.3 후속 챕터

9.5 카테고리 진입점

Subscribe

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