DAG 를 0 부터 짓기 — 호텔 예약 사례로 보는 4 단계 레시피 (Buisson Ch.4 overview)

전문가 없이 직접 DAG 를 구축하는 단계 — 후보 식별 → 검증 → 반복 → 단순화

Buisson (2021) Ch.4 의 전체 흐름을 압축한 overview. 도메인 전문가가 없을 때 분석가가 0 에서 출발해 DAG 를 짓는 4 단계 레시피를 정리한다. 호텔 예약 사례 (NRDeposit → IsCanceled) 를 사용하여 후보 변수 식별, 데이터로 검증, 반복적 정제, 단순화의 흐름을 직관·시연한다.

Experimentation
Causal Inference
저자

Kwangmin Kim

공개

2026년 05월 08일

1 정의

정의: DAG 구축의 4 단계 레시피

비즈니스 분석가가 도메인 전문가의 도움 없이 0 에서 출발해 사용 가능한 DAG 를 짓는 절차 (Buisson, 2021, Ch.4).

1. 후보 변수 식별 (Identify candidate variables)
        ↓
2. 포함 여부 결정 (Determine if to include)
        ↓
3. 반복 (Iterate)
        ↓
4. 단순화 (Simplify)

각 단계는 도메인 직관과 데이터 검증의 왕복 으로 진행. 한 번의 통과로 끝나지 않음.

직관 — Cunningham 의 인용

“[Causal Diagram] 은 연구 대상 현상에 대한 최신 지식의 이론적 표현이어야 한다. 그것은 전문가가 그것 자체라고 말할 수 있는 것이며, 그 전문성은 다양한 출처에서 나온다 — 경제 이론, 다른 과학 모델, 전문가와의 대화, 자신의 관찰과 경험, 문헌 검토, 자신의 직관과 가설.”

— Scott Cunningham, Causal Inference: The Mixtape (2021)

핵심: DAG 는 누군가의 머릿속 지식의 외화 (externalization) 다. 학술 분야 (역학, 경제학) 에서는 이미 정립된 모델이 있어 출발점을 제공.

비즈니스 분석에서는 ?

→ “당신이 조직의 첫 행동 과학자다” 가정. 처음부터 직접 짓는다.

2 개념 및 원리 — 4 단계의 의미

2.1 단계 0: Starter CD — 단일 화살표

출발

가장 단순한 시작:

Cause of Interest ──→ Effect of Interest

분석 질문이 명확해야 시작 가능. 이 한 줄이 모든 분석의 뿌리.

호텔 예약 사례:

NRDeposit (환불 불가 보증금) ──→ IsCanceled (예약 취소)

분석 질문: “환불 불가 보증금이 예약 취소율에 영향을 주는가?”

직관 — 출발점의 명확성

분석가가 자주 빠지는 함정: “분석 질문이 모호한 채 분석 시작.”

“데이터를 좀 보자… 뭔가 패턴이 있을 것 같으니…”

이 자세는 데이터 dredging 으로 이어짐 — 우연한 상관을 인과로 오인.

대신 권장: 분석 시작 전 한 줄 starter CD 를 그린다.

{질문하고 싶은 변수} ──→ {궁금한 결과 변수}

이 한 줄이 명확하지 않으면, 분석을 시작하지 않음. 비즈니스 파트너와 다시 대화해 질문을 명확히 한 후 시작.

2.2 단계 1: 후보 변수 식별

“있는 데이터부터 보자” 의 함정

자연스러운 직감: “회사 데이터베이스를 열어 보자. 어떤 컬럼들이 있는가.”

Buisson 의 비유:

“취객이 집 열쇠를 찾을 때, 잃어버린 곳이 아니라 가로등 아래에서 찾는다. 빛이 거기에 더 많기 때문에.”

데이터에 있는 변수만 보면:

  • WYSIATI (What You See Is All There Is) 편향 — Kahneman 의 용어
  • 진짜 중요한 변수 (데이터에 없는 변수) 를 놓침
  • 데이터의 정의를 액면 그대로 받아들임

대신 권장: 행동 카테고리 (Ch.2 의 5 요소) 부터 시작.

5 카테고리 + 시간 추세

후보 변수를 다음 6 카테고리에서 brainstorm.

                             ┌── Past Actions
                             ├── Intentions
   {Cause}                   ├── Cognition & Emotions
       ↓        ←── 영향 ──── ┤
   {Effect}                  ├── Personal Characteristics
                             ├── Business Behaviors
                             └── Time Trends

호텔 사례에서 각 카테고리:

  • Past Actions: 과거 취소 이력, 재방문 고객 여부
  • Intentions: 여행 사유, 취소 사유
  • Cognition & Emotions: 보증금 약관 이해도, sunk cost 인지
  • Personal Characteristics: 나이, 국적, 가족 구성
  • Business Behaviors: 예약 채널, 시장 세그먼트, 고객 유형
  • Time Trends: 분기, 연도 (계절성·추세)
직관 — 왜 이 5 카테고리인가

Buisson 의 행동 5 요소 (Ch.2) 는 인간의 모든 행동을 단계적으로 분해한다.

  • Personal — 누구인가 (변하지 않는 특성)
  • Cognition — 어떻게 인지하는가 (믿음, 정보)
  • Intention — 무엇을 의도하는가 (계획)
  • Action — 무엇을 하는가 (행동)
  • Business — 시스템과 어떻게 상호작용하는가

이 5 카테고리를 모두 점검하면 빠지는 변수가 거의 없음. 비즈니스 행동 분석의 체크리스트.

→ 분석가가 매 단계 “이 카테고리에서 빠진 변수는?” 자문. 처음 떠오른 1~2개 변수만으로 분석을 시작하지 않음.

2.3 단계 2: 포함 여부 결정 — 데이터로 검증

후보 변수의 선별

식별된 후보 중 어떤 것을 CD 에 포함할지 결정:

  • 후보가 분석 대상 (treatment, outcome) 과 통계적으로 연관되어 있는가?
  • 통계적 연관이 있으면 인과 가설을 정당화할 만한가?
  • 인과 가설이 정당하면 어떤 방향의 화살표를 그릴까?

검증 도구:

  • 연속·연속: 상관 계수 (Pearson)
  • 범주·연속: 일원 분산분석 (one-way ANOVA), \(\eta^2\)
  • 범주·범주: Cramer’s V, 카이 제곱 검정
  • 다중 변수: VIF (다중공선성 진단)
직관 — 통계만으로 결정 안 함

중요: 통계적 연관이 있어도 도메인 직관과 부합 안 하면 화살표 안 그림.

예: 호텔 데이터에서 “예약 시 객실 번호 = 7층” 과 “취소율” 사이 통계적 연관이 있어도, 도메인 직관 (“층수가 행동의 원인이 아님”) 으로 인과 화살표 안 그림.

반대로: 통계적 연관이 없어도 도메인 직관이 강하면 화살표 그려둘 수 있음. 데이터로 미반박된 것이지 부재 증명 아님.

→ 통계는 편집자, 도메인 직관은 저자. 저자가 쓴 글을 편집자가 다듬지만, 편집자가 글을 쓰지 않음.

검증 워크플로
후보 변수 X 가 있다고 하자.

Q1: X 와 Treatment (T) 의 통계적 연관?
   No → X 가 confounder 일 가능성 ↓ (제외 후보)
   Yes → Q2 진행

Q2: X 와 Outcome (Y) 의 통계적 연관?
   No → X 가 confounder 일 가능성 ↓ (제외 후보, T 의 mediator 일 수 있음)
   Yes → Q3 진행

Q3: X 의 시점이 T 보다 앞인가?
   Yes → X 가 confounder 후보. 인과 방향 X → T, X → Y
   No → X 가 mediator 일 가능성

Q4: 도메인 직관과 부합?
   Yes → CD 에 포함
   No → CD 에서 제외 또는 추가 검증

2.4 단계 3: 반복

직관 — 한 번의 통과로 끝나지 않는다

한 변수를 추가하면 다른 변수의 역할이 바뀔 수 있다.

호텔 사례:

  1. 처음에 NRDeposit → IsCanceled 만 그림.
  2. 발견: NRDeposit 이 있는 예약의 95% 가 취소됨 (vs 없는 경우 27%).
  3. “직관에 어긋남 — 보증금이 취소를 부추기지 않을 텐데”
  4. 가설: 호텔이 위험이 높은 예약 (PriorCancellationRisk) 에 NRDeposit 를 부과 → confounder.
  5. CD 갱신: PriorCancellationRisk → NRDeposit, PriorCancellationRisk → IsCanceled.
  6. PriorCancellationRisk 의 proxy 변수 (PreviousCancellation, IsRepeatedGuest) 를 회귀에 포함.
  7. 새 회귀: NRDeposit 의 효과가 줄어들거나 양 → 음 으로 바뀌는지 점검.
  8. 결과 해석 → 추가 변수 brainstorm → 반복.

→ DAG 는 살아있는 문서. 분석이 진행되며 진화.

2.5 단계 4: 단순화

직관 — 분석 목적에 맞게 가지치기

최종 DAG 가 너무 복잡하면 의사결정·의사소통이 어려워짐.

단순화 방법:

  1. Chain 축약: mediator 제거 (분석 대상이 아니면)
  2. Aggregation: 같은 역할의 변수들 통합 (Age, Gender → Demographics)
  3. 약한 화살표 제거: 효과가 작은 화살표는 무시 (1차 근사)
  4. 분석 대상 외 변수 가지치기: backdoor path 차단에 필요 없는 변수 제거

남은 DAG 가 분석에 필요한 최소 형태.

3 호텔 예약 사례 — 4 단계 적용

3.1 비즈니스 문제

데이터셋

Antonio 외 (2019) 의 호텔 예약 데이터. 두 호텔의 약 87000 건 예약.

주요 변수:

변수 설명 유형
NRDeposit 환불 불가 보증금 여부 0/1
IsCanceled 예약 취소 여부 0/1
DistributionChannel 예약 채널 (Direct, Corporate, TA/TO, Other) 범주
CustomerType 고객 유형 (Transient, Group, Contract) 범주
MarketSegment 시장 세그먼트 범주
Children 동반 아동 수 정수
ADR 일평균 객실료 수치
PreviousCancellation 과거 취소 이력 0/1
IsRepeatedGuest 재방문 고객 0/1
Country 국적 범주
Quarter, Year 예약 시점 범주

3.2 단계 0: Starter CD

NRDeposit ──→ IsCanceled
첫 발견 — 직관에 어긋나는 결과
취소 안 함 취소함
보증금 없음 (NRDeposit=0) 73% 27%
보증금 있음 (NRDeposit=1) 5% 95%

해석 함정: “보증금이 취소를 더 부추긴다?”

상식 위반. 보증금을 받으면 취소가 줄어야지, 늘어나는 건 비논리적.

→ 이 직관 충돌이 confounder 의 신호.

3.3 단계 1: Confounder 후보 — Trip Risk

직관 — Behavioral Common Sense

“호텔이 환불 불가 보증금을 누구에게 요구하는가?”

답: 위험이 높은 예약 — 휴가철, 그룹, 외국인, 주말, 등.

[A priori cancellation risk]
       ↓               ↓
   NRDeposit ──→  IsCanceled

A priori cancellation risk 가 confounder. 호텔이 위험 평가 후 보증금 요구 → 위험 자체가 취소도 일으킴.

3.4 단계 1: 5 카테고리 후보 brainstorm

CD 확장
[Past Actions]      ─→ NRD ──→ Cancel
[Intentions]        ─→        ─↗
[Cognition]         ─→        ─↗
[Personal Char]     ─→        ─↗
[Business Behavior] ─→        ─↗
[Time Trends]       ─→        ─↗

각 카테고리에서 후보:

  • Past Actions: PreviousCancellation, IsRepeatedGuest
  • Intentions: TripReason, CancellationReason
  • Cognition: NRD 약관 이해, Sunk Cost 효과
  • Personal: Age, Country, Gender (데이터 일부만 있음)
  • Business: CustomerType, MarketSegment, DistributionChannel
  • Time Trends: Quarter, Year

3.5 단계 2: 검증 — Past Actions

직관 — PreviousCancellation 의 역할

가설: “과거 취소한 고객은 (1) 호텔이 NRD 부과 가능성 ↑, (2) 또 취소할 가능성 ↑”

PreviousCancellation
       ↓               ↓
   NRDeposit ──→  IsCanceled

검증:

  • PrevCancel & NRD 의 통계 연관: \(\chi^2\) 검정 → 강한 양의 연관
  • PrevCancel & Cancel 의 통계 연관: → 양의 연관
  • 시점: PrevCancel 이 NRD 결정 전임 (논리적)

→ 인과 방향 정당화. CD 에 포함.

3.6 단계 2: 검증 — Intentions

직관 — TripReason 은 데이터에 없다

데이터에 명시된 TripReason 컬럼 없음. 그러나 도메인 직관:

  • 휴가 여행 → NRD 가능성 ↑ (호텔 정책), 취소 가능성 ↑ (날씨·계획 변경)
  • 비즈니스 여행 → NRD 가능성 ↓, 취소 가능성 ↓ (회사 일정)

→ TripReason 을 미관측 confounder 로 CD 에 표기 (음영 노드).

[TripReason]  (미관측)
   ↓                ↓
NRDeposit ──→ IsCanceled

데이터에 없어도 그려둠. 나중에 인터뷰·외부 데이터로 측정 시도 가능.

직관 — CancellationReason — 다른 역할

CancellationReason 도 인터뷰로 측정 가능.

가설:

CancellationReason ──→ IsCanceled
                  ↑ (단방향, NRD 와 무관)

이유: 취소 사유는 예약 시점 (NRD 결정 시점) 에는 알려지지 않음. → NRD 의 원인 아님.

CancellationReason 은 IsCanceled 의 직접 원인일 뿐, NRD 와 IsCanceled 의 confounder 가 아님 → 회귀에 포함 안 해도 됨 (미관측).

3.7 단계 2: 검증 — Cognition & Emotions

직관 — 의사결정 시점 분석

분석가가 자문: “고객이 두 의사결정을 내리는 시점이 언제인가?”

  1. 예약 시점: 보증금 약관 이해도. NRD 약관을 이해 못 한 채 동의하는 비율?
  2. 취소 시점: NRD 를 sunk cost 로 인식. “이미 낸 돈이니 가서 묵자” vs “어차피 못 받으니 무시하고 취소”

이 두 인지 변수는 미관측. 하지만 CD 에 그려둠.

비즈니스 함의: 만약 약관 이해 부족이 큰 효과면 → 약관 명료화로 취소율 감소 가능.

3.8 단계 2: 검증 — Personal Characteristics

데이터의 한계

Country 만 있음. Age, Gender 등은 없음.

Country 의 역할: 미관측 변수의 proxy. 국가별로 여행 패턴, 결제 문화, 위험 수용도가 다름 → 국적이 미관측 personal characteristics 를 부분적으로 대표.

→ Country 를 confounder 로 회귀에 포함.

3.9 단계 2: 검증 — Business Behaviors

CustomerType, MarketSegment, DistributionChannel

이 세 변수는 서로 강한 상관 (Cramer’s V > 0.5) — 다중공선성 위험.

분석가의 결정:

  • 가장 의미 있는 변수 1~2개만 회귀에 포함 (예: MarketSegment)
  • 나머지는 CD 에 포함하되 회귀에서는 제외 (correlated 변수의 부수적 정보 흡수)

→ CD 와 회귀가 1:1 일치 안 함. CD 는 이론적 표현, 회귀는 식별 가능한 부분만.

3.11 단계 3: 반복

직관 — 변수 추가의 효과 점검

NRDeposit 의 IsCanceled 효과를 단계별로 추적:

모형 NRDeposit 의 효과 (odds ratio) 해석
단순 (NRD 만) OR ≈ 41 보증금 시 41배 더 취소 (가짜)
+ PrevCancel OR ≈ 30 줄었지만 여전히 큼
+ Country OR ≈ 25 더 줄음
+ MarketSegment OR ≈ 15 절반으로
+ Quarter, Year OR ≈ 10 줄어듦 (확실히 confounder)
+ IsRepeatedGuest OR ≈ 9 거의 안정

→ Confounder 를 추가할수록 OR 감소. 안정될 때까지 반복.

남은 OR 9 가 의미하는 것: 진짜 인과 효과가 아직 양수 — 보증금이 정말 취소를 부추기는 효과가 있을 수도, 또는 미관측 confounder (TripReason 등) 가 남아 있을 수도.

RCT (실험) 이 진정한 답을 줌. 무작위로 NRD 부과 → 취소율 비교.

3.12 단계 4: 단순화

직관 — 의사결정용 단순 CD

분석 대상이 명확해지면, 모든 변수를 CD 에 그릴 필요 없음.

호텔 분석의 최종 DAG (단순화):

PreviousCancellation
        ↓ ↓
       NRD → IsCanceled
        ↑   ↑
   [TripReason]
   (미관측)

이게 의사결정 보고용 의 핵심 DAG. 호텔 매니저에게 “이 분석은 PrevCancel 을 통제했고, TripReason 은 미관측 limitations 로 남았다” 설명 가능.

배경의 다른 변수 (Country, MarketSegment 등) 도 회귀에는 포함했으나 그림에서는 단순화.

4 응용 — 4 단계 레시피의 일반화

4.1 다른 비즈니스 문제에 적용

SaaS 사례 — Onboarding 효과

분석 질문: “Onboarding 튜토리얼이 사용자 retention 에 영향을 주는가?”

Starter:

TutorialCompleted ──→ Retention(30d)

5 카테고리 brainstorm:

  • Past Actions: 과거 다른 SaaS 사용 경험
  • Intentions: 사용 목적 (개인 vs 팀, 단기 vs 장기)
  • Cognition: 제품 학습 의지, 도움말 이해도
  • Personal: 직무, 기술 수준
  • Business: 가입 채널 (광고·검색·추천)
  • Time Trends: 가입 코호트 (월별 변화)

가설: “사용 목적이 강한 사용자가 (1) 튜토리얼 완료 ↑, (2) Retention ↑” → confounder.

→ Hotel 사례와 같은 패턴.

이커머스 사례 — 추천 효과

분석 질문: “맞춤 추천이 구매 전환을 높이는가?”

Starter:

RecommendationShown ──→ Purchase

후보 변수:

  • Past Actions: 이전 구매 빈도 (frequent buyer 가 추천도 더 받고 더 사고)
  • Intentions: 검색 시점 의도 (browsing vs 구매 의도 명확)
  • Personal: 인구통계, 카테고리 선호
  • Business: 디바이스, 시간대, 페이지

가설: “검색 알고리즘이 구매 의도가 높은 사용자에게 추천을 더 보여줌” → confounder.

→ A/B 테스트 (무작위 추천 노출) 가 진짜 답.

4.2 일반화된 워크플로

직관 — 4 단계의 본질
단계 본질 시간
1. 후보 식별 Brainstorm — 도메인 직관 1~2 일
2. 포함 결정 통계 + 직관 검증 3~7 일
3. 반복 새 데이터·인터뷰로 정제 1~4 주
4. 단순화 보고용 가지치기 1 일

전체 약 1~6 주. 한 번의 분석에 한 달은 비현실적이라고 느끼면, 단계 3 (반복) 의 깊이를 줄여 1~2 주로.

→ DAG 는 분석의 부산물이 아니라 분석 그 자체. 시간을 들일 가치 있음.

5 코드 예시 — Python 으로 4 단계 시연 (가상 데이터)

import numpy as np
import pandas as pd
import statsmodels.api as sm
from scipy.stats import chi2_contingency

# 가상 호텔 예약 데이터
np.random.seed(42)
n = 5000

# 미관측 confounder: trip risk (0~1)
trip_risk = np.random.uniform(0, 1, n)

# Past Actions
prev_cancel = (np.random.uniform(0, 1, n) < 0.3 * trip_risk + 0.05).astype(int)

# Time Trend
quarter = np.random.choice([1, 2, 3, 4], n)
holiday_quarter = ((quarter == 4) | (quarter == 3)).astype(int)

# NRDeposit — risk 와 prev_cancel, holiday 영향
nrd_logit = -3 + 4 * trip_risk + 2 * prev_cancel + 1 * holiday_quarter
nrd_prob = 1 / (1 + np.exp(-nrd_logit))
nrd = (np.random.uniform(0, 1, n) < nrd_prob).astype(int)

# IsCanceled — risk, prev_cancel, holiday 영향 (NRD 자체는 영향 없음 — 가설)
cancel_logit = -1 + 2 * trip_risk + 1 * prev_cancel + 0.5 * holiday_quarter
cancel_prob = 1 / (1 + np.exp(-cancel_logit))
cancel = (np.random.uniform(0, 1, n) < cancel_prob).astype(int)

df = pd.DataFrame({
    "NRDeposit": nrd,
    "IsCanceled": cancel,
    "PrevCancellation": prev_cancel,
    "HolidayQuarter": holiday_quarter,
    "TripRisk_unobs": trip_risk,
})

# 단계 0: Starter — 단순 회귀
print("=== 단계 0: NRDeposit → IsCanceled (단순) ===")
X0 = sm.add_constant(df["NRDeposit"])
m0 = sm.Logit(df["IsCanceled"], X0).fit(disp=False)
print(f"  OR(NRD) = {np.exp(m0.params['NRDeposit']):.2f}")

# 단계 2: Confounder 추가
print("\n=== 단계 2: + PrevCancellation, HolidayQuarter ===")
X2 = sm.add_constant(df[["NRDeposit", "PrevCancellation", "HolidayQuarter"]])
m2 = sm.Logit(df["IsCanceled"], X2).fit(disp=False)
print(f"  OR(NRD) = {np.exp(m2.params['NRDeposit']):.2f}")

# 단계 2 (idealized): 미관측 confounder 도 보정
print("\n=== 가상: + TripRisk (미관측, 정답 참고용) ===")
X3 = sm.add_constant(df[["NRDeposit", "PrevCancellation", "HolidayQuarter", "TripRisk_unobs"]])
m3 = sm.Logit(df["IsCanceled"], X3).fit(disp=False)
print(f"  OR(NRD) = {np.exp(m3.params['NRDeposit']):.2f} ← ~1 이면 진짜 효과 0")
직관 — 시뮬레이션의 메시지

예상 결과:

  • 단계 0 (단순): OR ≈ 8 (강한 양의 효과로 보임)
  • 단계 2 (관측 confounder): OR ≈ 3 (줄어듦)
  • 가상 (미관측 포함): OR ≈ 1 (진짜 효과 ~ 0)

이 시뮬레이션은 진짜 데이터의 NRDeposit 효과가 0 이라고 가정했지만, 미관측 trip_risk 가 NRD 와 IsCanceled 모두에 영향을 줘서 가짜 양의 상관 발생.

관측 confounder (PrevCancel, HolidayQuarter) 만으로 부분적 보정 — TripRisk 의 일부를 흡수.

현실 분석에서는 단계 2 의 결과 (OR ≈ 3) 를 가지고 결론지음. “보증금이 취소를 3 배로 늘림” — 그러나 이게 진짜 효과인지, 미관측 잔여 confounder 인지 결정 못함.

해결: RCT 또는 instrumental variable.

5.1 변수 검증 — Cramer’s V

def cramers_v(x, y):
    """두 범주 변수의 Cramer's V."""
    confusion = pd.crosstab(x, y)
    chi2, p, dof, expected = chi2_contingency(confusion)
    n = confusion.values.sum()
    r, k = confusion.shape
    return np.sqrt(chi2 / (n * (min(r, k) - 1)))

# 변수 간 연관 점검
print("\n=== 변수 간 Cramer's V ===")
print(f"NRD ↔ PrevCancel: {cramers_v(df['NRDeposit'], df['PrevCancellation']):.3f}")
print(f"NRD ↔ HolidayQuarter: {cramers_v(df['NRDeposit'], df['HolidayQuarter']):.3f}")
print(f"PrevCancel ↔ Cancel: {cramers_v(df['PrevCancellation'], df['IsCanceled']):.3f}")
print(f"HolidayQuarter ↔ Cancel: {cramers_v(df['HolidayQuarter'], df['IsCanceled']):.3f}")
직관 — Cramer’s V 해석
Cramer’s V 의미
0 통계적 독립
0.1 약한 연관
0.3 중간
0.5+ 강함

비즈니스 분석 임계값: V > 0.1 이면 회귀에 포함 고려, V > 0.3 이면 거의 확실히 포함.

→ 자동화된 변수 선별 도구. 모든 후보를 일일이 통계 검정하는 시간 절약.

6 관련 주제

6.1 Ch.4 의 형제 글

6.2 이전 챕터

6.3 후속 챕터

6.5 카테고리 진입점

Subscribe

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