DCC — 분리적 원인 기준의 정의·강점·한계 (Buisson Ch.5.1)

안전 우선의 변수 선택 규칙 — sufficient but not necessary 의 의미

Buisson (2021) Ch.5 의 첫 번째 변수 선택 규칙인 Disjunctive Cause Criterion (DCC) 을 자세히 정리한다. DCC 의 정의를 4 부분으로 분해하고, sufficient 의 통계적 의미, CD 부정확성에 대한 robust 함, redundancy 의 비용, 미관측 변수의 한계를 C-Mart 사례와 시뮬레이션으로 시연한다.

Experimentation
Causal Inference
저자

Kwangmin Kim

공개

2026년 05월 08일

1 정의

정의: Disjunctive Cause Criterion (DCC)

“Treatment 또는 Outcome 의 직접 원인 (direct cause) 인 모든 변수를 회귀에 통제 변수로 포함한다. 단, treatment 와 outcome 사이의 mediator 는 제외한다.”

(Buisson, 2021, Ch.5; VanderWeele & Shpitser, 2011)

수식:

\[ \text{Controls}_{\text{DCC}} = \underbrace{\{V : V \to T\}}_{\text{T 의 원인}} \cup \underbrace{\{V : V \to Y\}}_{\text{Y 의 원인}} \setminus \underbrace{\{V : T \to V \to Y\}}_{\text{mediator}} \]

직관 — Disjunctive 의 의미

“Disjunctive” = “OR” (논리 합).

DCC = “T 의 원인 OR Y 의 원인” 모두 포함 → 둘의 합집합.

대조 (Conjunctive 관점): “T 의 원인 AND Y 의 원인” 만 = confounder 만.

DCC 는 confounder 를 정확히 식별하지 않고도 그것을 포함하는 더 큰 집합을 통제 → confounder 를 빠뜨릴 위험 없음.

→ “Confounder 를 정확히 모를 때 안전한 보험”.

2 개념 및 원리 — DCC 의 4 부분 분해

2.1 1. “모든 직접 원인 (direct cause)”

“직접” 의 의미

CD 에서 한 화살표만 거치는 부모 노드.

A ──→ T  : A 는 T 의 직접 원인
A ──→ B ──→ T : A 는 T 의 ancestor (간접). DCC 가 직접 요구하지 않음

그러나 chain collapsing 의 효과로:

A ──→ B ──→ T  ↔  A ──→ T (collapse)

A 가 chain 을 통해 T 의 effective cause 가 됨. 따라서 DCC 가 “직접 원인” 만 요구해도 chain 을 통해 간접 원인의 효과를 흡수.

직관 — Chain Collapsing 의 신뢰

DCC 가 “직접 원인” 만 요구하는 이유:

  • CD 에서 “A → B → T” 로 표현된 chain 은 collapse 가능 → “A → T” 와 등가
  • A 가 직접 원인이든 간접 원인이든 회귀 효과는 동일 (chain 의 양 끝)
  • 따라서 직접 원인 통제만으로 confounding path 차단

이 통찰이 DCC 의 효율을 만든다. 모든 ancestor 를 통제할 필요 없음 — 직접 원인만으로 충분.

2.2 2. “T 또는 Y 의” — 두 변수 모두 처리

OR 의 통계적 의미

DCC 가 통제할 변수:

  • T 의 원인만 (Y 와 무관) — confounder 아니지만 통제됨 (불필요, but 안전)
  • Y 의 원인만 (T 와 무관) — confounder 아니지만 통제됨 (불필요, but 안전)
  • T 와 Y 의 공통 원인 (confounder) — 반드시 통제해야 함

핵심: 세 번째 (confounder) 가 첫 번째와 두 번째의 공통 부분에 포함되므로, OR 합집합이 confounder 를 자동 포함.

수학적으로:

\[\{V : V \to T\} \cap \{V : V \to Y\} \subseteq \{V : V \to T\} \cup \{V : V \to Y\}\]

직관 — Venn Diagram 으로
        T 의 원인               Y 의 원인
       ┌──────────┐           ┌──────────┐
       │          │           │          │
       │   ┌──────┼─────┐     │          │
       │   │      │     │     │          │
       │   │ Conf │     │     │          │
       │   └──────┼─────┘     │          │
       │          │           │          │
       └──────────┘           └──────────┘

DCC = 두 원의 합집합 (가운데 confounder 포함).

분석가가 confounder 영역을 정확히 모를 때:

  • “정확한 confounder 만 통제” → 실수로 빠뜨릴 위험
  • “전체 합집합 통제” → 빠뜨림 없이 안전

→ DCC 의 안전 보장 메커니즘.

2.3 3. “Mediator 제외”

Mediator 통제의 위험
T ──→ M ──→ Y

M (mediator) 을 통제하면:

  • T 의 직접 효과 (M 우회 경로) 만 추정
  • T 의 mediator 경로 효과는 차단됨
  • 분석 목적이 “총 효과 (total effect)” 면 이게 잘못된 결과

비유: 도미노 A → B → C 에서 B 를 잡고 있으면 A 가 쓰러져도 C 가 안 쓰러짐. A 의 “총 효과” 가 0 으로 보임.

→ Mediator 는 절대 통제 안 함 (총 효과 분석 시).

직관 — Mediator 식별이 어려운 이유

MarketingEmail → Engagement → Purchase 구조에서 Engagement 가 mediator.

만약 분석가가 “Engagement 가 강한 confounder” 라고 잘못 식별하고 통제 → over-adjustment, MarketingEmail 의 효과가 가려짐.

이걸 피하려면:

  1. 시간 선후 점검: T 가 발생한 후 M 이 발생하면 M 은 T 의 자식 → mediator
  2. 도메인 직관: “M 이 T 의 영향을 받아 Y 에 전달” 의미가 있는가
  3. 데이터 검증: T 통제 후 M 이 Y 에 강한 영향이면 mediator 가능성

→ Mediator 식별은 분석 설계의 핵심.

2.4 4. “Removes confounding” — 충분 (Sufficient)

Sufficient vs Necessary

DCC 의 보장:

  • Sufficient: DCC 의 변수를 모두 통제하면 confounding 제거. 보장됨.
  • Not Necessary: DCC 가 요구하는 변수 중 일부는 사실 confounding 에 무관 (Y 만의 원인이거나 T 만의 원인). 통제 안 해도 OK.

→ DCC = “안전 우선” 의 over-engineering. 진짜 필요한 변수보다 더 많이 통제.

비유: 보험. 안 일어날 일에도 보험 들면 비용 발생, 단 일어난다면 보험이 보호.

직관 — 왜 “충분” 으로 만족하는가

분석가가 confounder 를 정확히 식별 못할 때:

  • “Necessary 만” 통제 시도 → 실수 가능 → confounding 잔존
  • “Sufficient 모두” 통제 → 실수해도 confounder 빠뜨림 없음

대신 비용:

  • 더 많은 변수 → 더 많은 데이터 필요
  • 표준 오차 약간 ↑ (자유도 ↓)
  • 계수 해석 부담 ↑

→ 정확도 vs 안전성 trade-off. 분석 초기 단계에서는 안전 우선.

3 DCC 의 강점 — CD 부정확성에 대한 Robust

3.1 CD 의 누락된 화살표를 흡수

직관 — DCC 의 magic

마케팅 팀이 CD 를 그렸으나 어떤 화살표를 빠뜨림:

실제 CD:
NumberOfCustomers ──→ IceCreamSales
NumberOfCustomers ──→ BurgerSales ──→ FrenchFrySales ──→ BottledWaterSales

분석가의 CD (위쪽 chain 누락):
NumberOfCustomers ──→ IceCreamSales
                        FrenchFrySales ──→ BottledWaterSales

분석가는 NumberOfCustomers 가 BottledWaterSales 와 어떻게 연결되는지 모름.

DCC 적용:

  • T (IceCreamSales) 의 원인: NumberOfCustomers
  • Y (BottledWaterSales) 의 원인: FrenchFrySales

→ NumberOfCustomers + FrenchFrySales 둘 다 통제.

신기한 점: 누락된 chain (NumberOfCustomers → BurgerSales → FrenchFrySales → BottledWaterSales) 의 confounding 을 NumberOfCustomers 통제로 자동 차단.

→ DCC 가 CD 의 부분 부정확성을 보상.

3.2 DCC 의 견고성 (Robustness)

분석가가 만드는 흔한 실수와 DCC 의 대응
분석가의 실수 결과 DCC 가 대응?
Path 일부 누락 confounder 식별 실패 ✓ 다른 cause 통제로 흡수
화살표 방향 반대로 그림 confounder 가 아닌 변수 통제 ✓ 영향 없음 (over-control 만)
일부 confounder 빠뜨림 (변수 자체) 잔여 confounding ✗ 변수 자체가 없으면 통제 불가
Mediator 식별 실패 over-adjustment ✗ DCC 가 mediator 제외 못 하면 잘못된 추정

→ DCC 는 “구조적 실수” 에 robust, “변수 누락” 또는 “mediator 식별 실패” 에는 취약.

4 DCC 의 한계

4.1 한계 1: Redundancy

불필요한 통제

C-Mart Block 1:

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

DCC: NumberOfCustomers + FrenchFrySales 통제.

진짜 필요: NumberOfCustomers 만 (그것만으로 path 자동 차단).

→ FrenchFrySales 통제는 redundant. 자유도 손실, 표준 오차 증가.

이 redundancy 비용은 일반적으로 작지만 변수 많을 때 누적.

4.2 한계 2: 미관측 변수

데이터가 없으면 적용 불가

C-Mart Block 2:

[AverageCustomerAge] ──→ IceCreamSales
[CustomerHealthMindset] ──→ BottledWaterSales

DCC 가 요구: AverageCustomerAge + CustomerHealthMindset 통제.

문제: 두 변수 모두 미관측 (개별 sale 단위 측정 불가).

→ DCC 적용 불가. 분석가는 “잔여 confounding 가능” 명시.

이 한계는 BC 가 보완 (E-BUI5-2). BC 는 collider 의 자연 차단을 활용해 미관측 변수를 우회 가능.

4.3 한계 3: Effect Modifier 처리

직관 — Effect Modifier 와 Confounder 의 차이
M (modifier)
   ↓
T → Y

M 이 T → Y 효과의 크기를 변경 (예: M = 1 일 때 효과 큼, M = 0 일 때 작음).

DCC 는 M 을 cause of T or Y 로 보면 통제 변수에 포함. 그러나:

  • Effect modifier 통제 → 평균 효과 추정 (가능)
  • Effect modifier 분석 → 조건부 효과 (subgroup analysis) 필요

DCC 는 후자를 자동으로 안 함. 분석가가 별도로 분리해야.

→ DCC 는 “변수 선택” 만 다루지 “효과의 모형화” 는 별도.

5 응용 — DCC 의 비즈니스 사례

5.1 호텔 NRD 사례

DCC 적용

CD (E-BUI4 의 단순화된 버전):

Personal Char  PrevCancel  ADR  Country
       ↓           ↓        ↓     ↓
       └────→ NRDeposit ──→ IsCanceled
       └─────────────────────↗
       └─────────────────────↗
       └─────────────────────↗

NRDeposit 의 직접 원인: Personal Char, PrevCancel, ADR, Country IsCanceled 의 직접 원인: Personal Char, PrevCancel, ADR, Country, NRDeposit Mediator (NRD → ? → Cancel): 없음 (NRD 가 Cancel 의 직접 원인)

DCC: Personal Char + PrevCancel + ADR + Country + (NRD 자체).

회귀:

sm.Logit(Cancel, [NRD, PersonalChar, PrevCancel, ADR, Country])

이게 DCC 처방.

5.2 SaaS Onboarding 사례

DCC 적용

CD:

PastExp  JobRole  Cohort  SignupChannel
   ↓        ↓       ↓          ↓
   └────→ Tutorial ──→ Retention
   └────────────────────↗
   └────────────────────↗
   └────────────────────↗

Tutorial 의 직접 원인: PastExp, JobRole, SignupChannel Retention 의 직접 원인: PastExp, JobRole, Cohort, SignupChannel, Tutorial Mediator: 없음

DCC: PastExp + JobRole + Cohort + SignupChannel + Tutorial 통제.

→ Cohort 가 Tutorial 의 원인 아니더라도 (Y 의 원인이므로) DCC 가 통제 요구. 이게 BC 와 차이 (BC 는 Cohort 무시 가능 — 다음 글).

6 DCC 적용 알고리즘

5 단계 절차
1. CD 확인 (T, Y 결정 + 모든 화살표)
2. T 의 직접 원인 집합 P_T 구하기
3. Y 의 직접 원인 집합 P_Y 구하기
4. Mediator (T → ? → Y 의 중간 노드) 식별
5. 통제 변수 = (P_T ∪ P_Y) \ Mediators \ {T, Y}

이 절차가 알고리즘적이라는 사실 — 자동화 가능.

6.1 DCC 의 Sufficient 증명 (간단 버전)

직관 — 왜 DCC 가 작동하는가

증명 스케치:

  1. Confounder C 의 정의: C → T AND C → Y (양방향 화살표 또는 fork)
  2. DCC 가 T 의 모든 원인 통제 → C 가 T 의 원인이므로 C 통제됨
  3. C 통제 → T 와 Y 사이 C 를 통한 noncausal path 차단
  4. Mediator 가 아니므로 T → Y 의 causal path 는 차단 안 됨
  5. 따라서 confounding 제거.

이 추론에 사용된 가정:

  • CD 의 모든 화살표는 정확
  • Mediator 는 정확히 식별됨
  • 모든 cause 가 측정됨

→ 가정이 깨지면 DCC 도 깨짐. 그러나 일부 화살표 누락에는 robust.

7 코드 예시 — DCC 자동화 + 시뮬레이션

7.1 DCC 식별 자동화

import networkx as nx

def identify_dcc_controls(G, T, Y):
    """
    DCC 에 따른 통제 변수 자동 식별.

    Parameters
    ----------
    G : networkx.DiGraph
    T, Y : str (treatment, outcome 노드 이름)

    Returns
    -------
    set of str (통제 변수)
    """
    # Direct causes of T and Y
    causes_T = set(G.predecessors(T))
    causes_Y = set(G.predecessors(Y))

    # Mediators: T → ? → Y
    descendants_T = nx.descendants(G, T)
    candidates_Y_parents = set(G.predecessors(Y))
    mediators = descendants_T & candidates_Y_parents

    # DCC = (causes_T ∪ causes_Y) \ mediators \ {T, Y}
    controls = (causes_T | causes_Y) - mediators - {T, Y}
    return controls


# 호텔 사례
G_hotel = nx.DiGraph()
G_hotel.add_edges_from([
    ("PersonalChar", "NRDeposit"),
    ("PersonalChar", "IsCanceled"),
    ("PrevCancel", "NRDeposit"),
    ("PrevCancel", "IsCanceled"),
    ("ADR", "NRDeposit"),
    ("ADR", "IsCanceled"),
    ("Country", "NRDeposit"),
    ("Country", "IsCanceled"),
    ("NRDeposit", "IsCanceled"),
])

print("=== 호텔 사례 — DCC ===")
controls = identify_dcc_controls(G_hotel, "NRDeposit", "IsCanceled")
print(f"통제 변수: {sorted(controls)}")
print(f"  → 회귀: IsCanceled ~ NRDeposit + {' + '.join(sorted(controls))}")
직관 — 자동화의 가치

분석가가 DCC 를 손으로 적용하면:

  • CD 가 복잡할수록 시간 소요
  • mediator 식별에 실수 가능
  • “혹시 빠뜨린 변수 있나” 불안

자동화:

  • 즉시 결과
  • 명확한 알고리즘 (재현 가능)
  • 분석가는 결과 검토만

→ 비즈니스 분석 파이프라인에 DCC 자동화 함수를 표준화.

7.2 DCC 적용 vs 비적용 비교

import numpy as np
import pandas as pd
import statsmodels.api as sm

np.random.seed(42)
n = 5000

# 데이터 생성
trait = np.random.normal(0, 1, n)
prev_cancel = (trait * 0.5 + np.random.normal(0, 1, n) > 0).astype(int)
adr = trait * 30 + np.random.lognormal(4.5, 0.3, n) * 0.5
country = (trait * 0.3 + np.random.normal(0, 1, n)).clip(-3, 3)

# Treatment
nrd_logit = -3 + 1 * trait + 1.5 * prev_cancel + 0.02 * adr
nrd_prob = 1 / (1 + np.exp(-nrd_logit))
nrd = (np.random.uniform(0, 1, n) < nrd_prob).astype(int)

# Outcome — 진짜 NRD 효과 = 0
cancel_logit = -1 + 0.8 * trait + 0.5 * prev_cancel + 0.01 * adr + 0.0 * nrd
cancel_prob = 1 / (1 + np.exp(-cancel_logit))
cancel = (np.random.uniform(0, 1, n) < cancel_prob).astype(int)

df = pd.DataFrame({
    "NRD": nrd, "Cancel": cancel,
    "PrevCancel": prev_cancel, "ADR": adr, "Country": country,
})

# 회귀 1: NRD 만
print("=== 회귀 비교 ===")
m1 = sm.Logit(df["Cancel"], sm.add_constant(df["NRD"])).fit(disp=False)
print(f"\n[NRD 만] OR(NRD) = {np.exp(m1.params['NRD']):.2f}  (진짜 1)")

# 회귀 2: DCC (PrevCancel, ADR, Country 추가)
m2 = sm.Logit(df["Cancel"], sm.add_constant(df[["NRD", "PrevCancel", "ADR", "Country"]])).fit(disp=False)
print(f"\n[DCC] OR(NRD) = {np.exp(m2.params['NRD']):.2f}")

# 회귀 3: DCC + 잘못된 변수 (mediator 가정)
# 만약 분석가가 잘못해서 NRD → MisuseFlag → Cancel 의 mediator 로 가정한 변수를 통제하면
mediator_misclassified = nrd * 0.5 + np.random.normal(0, 1, n)
df["wrong_mediator"] = mediator_misclassified
m3 = sm.Logit(df["Cancel"], sm.add_constant(df[["NRD", "PrevCancel", "ADR", "Country", "wrong_mediator"]])).fit(disp=False)
print(f"\n[DCC + 잘못 추가] OR(NRD) = {np.exp(m3.params['NRD']):.2f}  ← over-adjustment 가능성")
직관 — DCC 의 robustness 시연

예상 결과:

  • NRD 만: OR ≈ 3 (강한 양의 가짜 — confounding)
  • DCC: OR ≈ 1 (정확)
  • DCC + 잘못 추가: OR ≈ 0.5 (over-adjusted)

DCC 가 적절히 적용되면 정확. 그러나 분석가가 추가 변수를 잘못 분류하면 함정.

→ DCC 자동화도 mediator 분류는 분석가의 책임.

7.3 DCC vs Hand-picked 비교

# 비교: DCC (전부) vs 정확한 confounder 만
m_dcc = sm.Logit(
    df["Cancel"],
    sm.add_constant(df[["NRD", "PrevCancel", "ADR", "Country"]])
).fit(disp=False)

m_minimal = sm.Logit(
    df["Cancel"],
    sm.add_constant(df[["NRD", "PrevCancel"]])  # 가장 강한 confounder 만
).fit(disp=False)

print("\n=== DCC 전부 vs 핵심 confounder 만 ===")
print(f"DCC 전부: OR = {np.exp(m_dcc.params['NRD']):.3f}, SE = {m_dcc.bse['NRD']:.3f}")
print(f"핵심만:   OR = {np.exp(m_minimal.params['NRD']):.3f}, SE = {m_minimal.bse['NRD']:.3f}")

print(f"\nSE 차이: DCC 가 {m_dcc.bse['NRD'] / m_minimal.bse['NRD'] * 100:.1f}% 의 표준 오차")
직관 — Redundancy 의 비용 측정

DCC vs 핵심 변수만:

  • 점추정: 거의 같음 (DCC 가 약간 더 정확할 가능성)
  • 표준 오차: DCC 가 약간 ↑ (불필요한 변수의 자유도 손실)

비즈니스 의사결정:

  • 변수 추가의 비용 (SE ↑) 가 작으면 DCC 채택 (안전)
  • 비용이 크면 (큰 표본 부족 등) BC 로 변수 최소화

대부분의 비즈니스 분석에서 표본 크기가 충분하므로 DCC 의 SE 비용은 무시 가능.

8 관련 주제

8.1 Ch.5 의 형제 글

8.2 이전 챕터

8.3 후속 챕터

8.5 카테고리 진입점

Subscribe

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