1 정의
DAG 구축의 단계 1 (Buisson, 2021, Ch.4):
- Starter CD: 분석 질문을 한 줄 화살표로 표현
- 데이터로 1차 점검: 단순 분포·교차표로 직관 충돌 식별
- Confounder 가설: 직관 충돌이 있으면 미관측 공통 원인 가설
- 6 카테고리 brainstorm: Past Actions, Intentions, Cognition, Personal, Business, Time Trends 에서 후보 변수 추출
분석가가 “후보 변수 식별” 단계에서 자주 빠지는 함정:
- 데이터 의존: “있는 컬럼만 본다” — 진짜 중요한 미관측 변수 놓침
- 첫 인상 의존: “처음 떠오른 1~2개로 시작” — 빠진 카테고리 발견 못 함
- 순서 의존: “데이터 → 가설” 순서 — Hypothesis-driven 이 아니라 Data-dredging
대신 권장:
“5 분 동안 6 카테고리에서 변수 brainstorm. 그 후에야 데이터 본다.”
이 한 가지 습관이 분석의 깊이를 결정한다.
2 호텔 예약 사례 — 비즈니스 문제 정의
2.1 데이터셋 소개
Antonio, Almeida, Nunes (2019) 의 공개 데이터셋. 같은 도시 두 호텔의 약 87000 건 예약 (City Hotel + Resort Hotel).
import pandas as pd
df = pd.read_csv("hotel_bookings.csv")
print(df.shape) # (87,395, 32)
print(df.columns.tolist())핵심 변수:
| 변수 | 설명 | 유형 |
|---|---|---|
| NRDeposit | 환불 불가 보증금 여부 | Binary |
| IsCanceled | 예약 취소 여부 | Binary |
| DistributionChannel | 예약 경로 | Categorical |
| CustomerType | 고객 유형 (Transient, Group, etc) | Categorical |
| MarketSegment | 시장 세그먼트 | Categorical |
| Children | 동반 아동 수 | Integer |
| ADR | 일평균 객실료 | Numeric |
| PreviousCancellation | 과거 취소 이력 | Binary |
| IsRepeatedGuest | 재방문 여부 | Binary |
| Country | 국적 | Categorical |
| Quarter, Year | 시점 | Categorical |
2.2 Starter CD
분석 질문:
“환불 불가 보증금이 예약 취소율에 영향을 주는가?”
비즈니스 동기:
- 만약 NRD 가 취소를 줄인다 → 모든 예약에 NRD 적용 (정책 강화)
- 만약 NRD 가 취소를 늘린다 → 의외 결과, 추가 조사 필요
- 만약 효과 없다 → 정책 변경 불필요
CD 시작:
NRDeposit (Y/N) ──→ IsCanceled (Y/N)
이 한 줄이 모든 분석의 뿌리.
2.3 데이터로 첫 점검 — 충격적 발견
IsCanceled = 0 IsCanceled = 1
NRDeposit = 0 63,316 (73%) 23,042 (27%)
NRDeposit = 1 55 (5%) 982 (95%)
NRD 없는 예약: 27% 취소 NRD 있는 예약: 95% 취소
상대 위험 (RR):
\[ RR = \frac{0.95}{0.27} \approx 3.5 \]
오즈 비 (OR):
\[ OR = \frac{0.95 / 0.05}{0.27 / 0.73} \approx 51 \]
NRD 가 있을 때 취소 odds 가 51 배 ?
상식:
“환불 안 해주는 보증금을 받으면, 사람들은 더 안 취소할 것이다 (못 환불받으니까).”
데이터:
“환불 불가 보증금이 있으면, 사람들이 95% 취소한다.”
두 진술이 충돌. 가능한 설명:
- Reverse causality: 취소가 보증금을 일으킨다? — 시점상 불가능 (보증금이 취소 전에 결정됨)
- Confounding: 보증금과 취소 양쪽에 영향을 주는 공통 원인이 있다.
- Selection bias: 분석 표본 자체가 편향됨? — 점검 필요
가장 가능성 높은 설명: Confounding.
→ 호텔이 위험을 평가한 후 “이 예약은 취소 가능성 높음” → NRD 부과 → 그 예약은 결국 취소됨.
위험 (a priori cancellation risk) 이 양쪽의 공통 원인.
2.4 Confounder 가설
[A priori cancellation risk]
↓ ↓
NRDeposit ──→ IsCanceled
A priori cancellation risk 는 미관측 변수. 호텔의 위험 평가 모델 (또는 직원의 직감) 에 들어 있는 정보.
이 단순한 갱신이 분석의 출발점을 완전히 바꾼다.
기존 질문: “NRD → Cancel 효과는?”
수정된 질문: “Risk 를 통제한 후 NRD → Cancel 효과는?”
후자가 진정한 인과 질문. 전자는 confounded 결과만 보여줌.
이 갱신된 DAG (Risk → NRD, Risk → Cancel) 를 동료에게 보여주면:
“맞아. 우리는 휴가철 예약·해외 단체에 NRD 를 강제해. 그런 예약이 자주 취소되지.”
“주말 예약·신용 등급 낮은 카드도 NRD 부과해.”
“최근 가격 인상 때문에 high-end 예약자들이 NRD 회피.”
→ 동료마다 다른 risk 측면을 알려줌. DAG 가 공통 언어 역할.
DAG 없이 단순 회귀만 돌리면 이런 정보가 분석으로 들어오지 않음.
2.5 이상적 답 — RCT
위 confounding 문제를 가장 깔끔히 해결하는 방법: RCT.
무작위 배정 (호텔이 위험 평가 무시)
↓
┌─ Group A ─→ NRD 부과 → 취소율 측정
└─ Group B ─→ NRD 없음 → 취소율 측정
↓
두 그룹의 취소율 차이 = NRD 의 진짜 인과 효과
문제:
- 호텔이 무작위로 NRD 적용을 거부할 수 있음 (위험 관리 정책상)
- 무작위 NRD 가 비즈니스 손실 (위험 예약을 그냥 받으면 취소되어 매출 손실)
- 윤리적 문제 (고객에게 임의로 다른 정책 적용)
RCT 가 어려우면? 관찰 데이터 + 다중 confounder 통제 로 차선책.
이게 Buisson Ch.4 의 나머지 절차.
3 후보 변수 brainstorm — 6 카테고리
3.1 데이터부터 보지 않는 이유
자연스러운 직감: “회사 DB 열어보자. 어떤 컬럼 있는지 보고 시작하자.”
Buisson 의 비유 (재방문):
“취객이 집 열쇠를 찾을 때, 잃어버린 곳이 아니라 가로등 아래에서 찾는다.”
문제점:
- WYSIATI 편향 (Kahneman): 보이는 게 전부라고 생각. 미관측 중요 변수 놓침.
- 데이터 정의 액면 수용: 컬럼 이름·정의를 그대로 받아들여, 행동을 정확히 측정하는지 의심 안 함.
- 카테고리 편향: 데이터의 분류 (
MarketSegment) 가 비즈니스 관점일 뿐, 행동 관점이 아닐 수 있음.
대신 권장: 6 카테고리에서 후보 brainstorm 후, 그 다음에 데이터 점검.
이 순서가 데이터 의존 편향을 방지.
3.2 6 카테고리 frame
NRDeposit ──→ IsCanceled
↑ ↑
│ │
├── 1. Past Actions
├── 2. Intentions
├── 3. Cognition & Emotions
├── 4. Personal Characteristics
├── 5. Business Behaviors
└── 6. Time Trends
각 카테고리는 E-BUI2-1 인간 행동 5 구성요소 에 도입. 시간 추세는 추가.
분석가의 절차: 각 카테고리에 대해
- 이 카테고리에서 NRD 와 Cancel 양쪽에 영향을 줄 만한 변수는 무엇인가?
- 영향이 있다고 직관적으로 판단되면 CD 에 추가
- 데이터 존재 여부와 무관하게 추가 (미관측이어도 그림)
3.3 카테고리 1: Past Actions
질문: “고객의 과거 행동 중 NRD 부과 또는 취소 결정에 영향을 주는 것은?”
후보:
- PreviousCancellation: 과거 취소 이력
- IsRepeatedGuest: 재방문 여부
- PreviousBookingsNotCanceled: 과거 정상 완료 예약 수
- PreviousLoyaltyTierProgress: 로열티 등급 진행
PreviousCancellation 의 영향:
- NRD 결정: 호텔이 “이 사람은 과거 취소했음 → NRD 강제” — 인과 화살표 PrevCancel → NRD
- 취소 의사: “과거 취소한 사람은 또 취소할 가능성” — 인과 화살표 PrevCancel → Cancel
→ PrevCancel 이 confounder. 양쪽으로 화살표.
PreviousCancellation
↓ ↓
NRDeposit ──→ Cancel
비즈니스 의미: 과거 취소를 통제하지 않으면, NRD 의 효과가 PrevCancel 의 효과와 섞임.
“분석 대상이 행동이면, 과거 행동이 좋은 예측 변수다.”
이유:
- 습관 (habit): 한 번 행동한 사람이 또 행동할 가능성 ↑
- 특성의 proxy: 미관측 personal characteristics 의 결과로서 과거 행동이 그 특성을 부분 노출
- 자기 강화: 과거 행동이 미래 환경 (호텔의 정책 적용) 을 만듦
→ 과거 행동을 항상 변수로 고려. 데이터에 있으면 회귀 포함, 없으면 미관측 노드로 그려둠.
3.4 카테고리 2: Intentions
질문: “고객의 의도 중 NRD 또는 Cancel 결정에 영향을 주는 것은?”
후보:
- TripReason (여행 사유): 휴가 / 비즈니스 / 가족 행사 / 의료
- CancellationReason (취소 사유): 일정 변경 / 가격 변동 / 비교 후 다른 호텔 선택
데이터에 명시적으로 없음. 그러나 인터뷰·설문으로 측정 가능.
[TripReason] (미관측)
↓ ↓
NRDeposit IsCanceled
TripReason 이 NRD 양쪽으로 영향을 주는 이유:
- 휴가 여행:
- NRD ↑: 호텔이 성수기·휴가철 예약에 NRD 강제
- Cancel ↑: 날씨, 일정 변경, 가족 사정으로 취소 가능성
- 비즈니스 여행:
- NRD ↓: 회사 카드, 표준 계약, NRD 면제
- Cancel ↓: 회사 일정 fixed, 변경 어려움
→ TripReason 이 강한 confounder. 데이터에 없어도 CD 에 표기. 회귀에 직접 못 넣지만, 다른 proxy (예: BookingChannel — 회사 카드 vs 개인) 로 부분 통제 가능.
NRD ──→ Cancel
↑
[CancellationReason]
(미관측)
CancellationReason 은 IsCanceled 의 직접 원인이지만 NRD 의 원인 아님.
이유: 취소 사유는 예약 시점에는 알려지지 않음. 호텔이 “취소 사유” 를 미리 알고 NRD 결정 안 함.
→ CancellationReason 은 confounder 가 아닌 직접 원인 (mediator 도 아님). NRD 효과 추정에 영향 없음 — 회귀에 포함 안 해도 됨.
이 구분이 분석가의 작업을 줄임. 모든 변수를 회귀에 넣을 필요 없음.
3.5 카테고리 3: Cognition & Emotions
질문: “고객의 인지·감정 상태 중 결정에 영향을 주는 것은?”
분석가의 도구: 의사결정 시점 분석.
시점 1: 예약 시
- 약관 이해도
- 가격 인지
- 호텔 평판 인지
- 보증금에 대한 거부감
시점 2: 잠재적 취소 시
- Sunk Cost 효과 ("이미 낸 돈이니 가서 묵자")
- 후회 회피 ("취소하면 손해")
- 다른 옵션 발견 (저렴한 호텔)
- 일정 변경 충격
UnderstandsNRD (약관 이해 여부) 미관측 변수:
- 이해 못 함 + NRD 있음 → 예약 후 일정 변경 시 그냥 취소 (보증금이 sunk 라는 인식 부족)
- 이해함 + NRD 있음 → 일정 변경 시 어떻게든 가서 묵음 (보증금 손실 회피)
→ 약관 이해도가 NRD 의 효과를 modify (effect modification).
비즈니스 함의: 약관 명료화 (큰 글씨, 두 번 확인) 가 취소율을 줄일 수 있음.
CD:
[UnderstandsNRD]
↓
NRD ──→ Cancel
(Effect modifier 표기 방식은 Ch.5 또는 Ch.11 에서 자세히)
TreatsNRDasSunkCost 미관측 변수.
행동 경제학 발견:
- 어떤 사람은 sunk cost 를 강하게 회피 (“이미 낸 돈이니 어떻게든 가야”)
- 어떤 사람은 sunk cost 를 무시 (“못 받을 돈이니 신경 안 써”)
NRD 가 있을 때 취소율은 이 인지 패턴에 의존.
[TreatsNRDasSunkCost]
↓
NRD ──→ Cancel
이 변수도 미관측. 그러나 CD 에 표기하면 분석의 한계가 명확해짐.
3.6 카테고리 4: Personal Characteristics
질문: “고객의 인구통계 특성 중 결정에 영향을 주는 것은?”
후보:
- Age: 데이터 없음 (호텔 데이터셋의 한계)
- Gender: 데이터 없음
- Country: 있음
- Income / SocialClass: 직접 없음, ADR (객실료) 로 proxy 가능
Country, [Age], [Gender], [Income]
↓ ↓
NRDeposit ──→ IsCanceled
Country 는 다음을 부분적으로 대표:
- 결제 문화 (선불·후불 선호)
- 여행 스타일 (단체·개인)
- 신용 카드 사용 패턴
- 시간대 (예약·취소 timing)
- 호텔 정책 친숙도
→ Country 자체가 인과 변수가 아니라, 미관측 personal characteristics 의 proxy.
회귀에 Country 를 dummy 변수로 포함하면, 미관측 변수의 일부가 통제됨. 완벽하지 않지만 차선.
3.7 카테고리 5: Business Behaviors
질문: “고객이 비즈니스 시스템과 어떻게 상호작용하는가?”
후보:
- CustomerType: Transient, Group, Contract, Transient-Party
- MarketSegment: Direct, Online TA, Offline TA, Group, Other
- DistributionChannel: Direct, TA/TO, Corporate, Other
→ 세 변수가 강하게 상관 (Cramer’s V > 0.5). 다중공선성 위험.
“MarketSegment = Online TA” 는 비즈니스 입장에서 분류 (호텔이 어느 채널에서 예약 받았는가).
행동 입장에서는 다른 분류가 더 의미 있을 수 있음:
- 개인 vs 단체 (CustomerType + Children)
- 자발적 vs 강제 (회사 출장 vs 개인 휴가)
- 즉흥 vs 계획 (예약 시점 vs 도착 시점 차이)
분석가의 선택지:
- 기존 비즈니스 분류 그대로 사용 → 빠름, 그러나 행동 lens 결여
- 새 변수 합성 (예: “Corporate + Children = 1 / Other = 0”) → 정밀, 시간 소요
Buisson 의 권장: 후자, 단 변수가 너무 많아지지 않도록 선별.
3.8 카테고리 6: Time Trends
질문: “예약·취소가 시간 (계절·연도) 에 따라 어떻게 변하는가?”
후보:
- Quarter: 계절성 (Q1~Q4)
- Year: 연도 (정책 변화·경제 상황)
- Month-of-week: 요일 효과 (주말 vs 평일)
Quarter, Year ──→ NRD
──→ Cancel
호텔 정책 변경 사례:
- 2019: 호텔이 NRD 정책 도입 → NRD 비율 ↑
- 2020 ~ 2021: COVID-19 → 취소율 폭증 + 호텔이 환불 정책 완화 → NRD 비율 ↓
만약 2019 와 2021 데이터를 함께 분석하면:
- 2019: NRD 많음, 취소 적음 (전체 시장이 안정)
- 2021: NRD 적음, 취소 많음 (시장 불안정)
→ 시간을 통제 안 하면 NRD 와 Cancel 사이 음의 상관처럼 보임 (실제 인과 효과와 정반대).
해결: Year, Quarter 를 회귀에 포함.
→ 시간은 거의 항상 confounder. 시계열 데이터 분석에서 시간 통제는 표준.
3.9 종합 — 후보 변수 CD
[TripReason] [Country] [UnderstandsNRD] Quarter, Year
↓ ↓ ↓ ↓
┌────────────────────────────────────────────────────────┐
│ │
│ PreviousCancellation │
│ IsRepeatedGuest │
│ CustomerType │
│ MarketSegment ──→ NRDeposit ──→ IsCanceled │
│ DistributionChannel ↗ │
│ ADR │
│ │
│ [TreatsNRDasSunkCost] ──→ Cancel (only) │
│ [CancellationReason] ──→ Cancel (only) │
│ │
└──────────────────────────────────────────────────────────┘
(괄호 [ ] 는 미관측)
이 CD 가 단계 1 의 산출물.
4 응용 — 다른 비즈니스 문제로 일반화
4.1 이커머스 — 추천 효과
“맞춤 추천이 구매 전환을 높이는가?”
Starter:
RecommendationShown ──→ Purchase
6 카테고리 brainstorm:
| 카테고리 | 후보 | 미관측? |
|---|---|---|
| Past Actions | 과거 구매 빈도, 마지막 구매 후 시간 | 있음 |
| Intentions | 검색 의도 (browsing vs 구매) | 미관측 |
| Cognition | 가격 비교 인지, 광고 학습 | 미관측 |
| Personal | 인구통계, 카테고리 선호 | 부분 |
| Business | 디바이스, 시간대, 페이지, 경로 | 있음 |
| Time Trends | 계절 (Black Friday 등) | 있음 |
→ 추천 알고리즘이 구매 의도 높은 사용자에게 추천을 더 보여줌 → confounder.
4.2 SaaS — Onboarding 효과
“Onboarding 튜토리얼이 retention 을 높이는가?”
Starter:
TutorialCompleted ──→ Retention(30d)
6 카테고리:
| 카테고리 | 후보 |
|---|---|
| Past Actions | 다른 SaaS 사용 경험 |
| Intentions | 사용 목적 (단기 vs 장기) |
| Cognition | 기술 학습 동기 |
| Personal | 직무, 회사 규모 |
| Business | 가입 채널 (광고·검색·추천) |
| Time Trends | 가입 코호트 (월별 변화) |
→ 사용 목적이 강한 사용자가 (1) 튜토리얼 완료 ↑, (2) Retention ↑ → confounder.
5 코드 예시 — Python 으로 1 차 점검
5.1 단순 교차표와 OR
import numpy as np
import pandas as pd
from scipy.stats import chi2_contingency
# 가상 호텔 데이터 생성
np.random.seed(42)
n = 87000
# 미관측 trip risk (TripReason 의 proxy)
trip_risk = np.random.beta(2, 5, n) # 0~1 범위
# NRD 결정 (위험 높으면 NRD)
nrd_prob = trip_risk * 0.3 + 0.01
nrd = (np.random.uniform(0, 1, n) < nrd_prob).astype(int)
# IsCanceled 결정 (위험 높으면 취소)
cancel_prob = trip_risk * 0.7 + 0.1
cancel = (np.random.uniform(0, 1, n) < cancel_prob).astype(int)
df = pd.DataFrame({
"NRDeposit": nrd,
"IsCanceled": cancel,
"trip_risk": trip_risk,
})
# 단순 교차표
crosstab = pd.crosstab(df["NRDeposit"], df["IsCanceled"])
print("=== 단순 교차표 ===")
print(crosstab)
# 비율
crosstab_pct = pd.crosstab(df["NRDeposit"], df["IsCanceled"], normalize="index")
print("\n=== 행 비율 ===")
print(crosstab_pct)
# Odds Ratio
a, b = crosstab.values[0]
c, d = crosstab.values[1]
or_value = (d * a) / (b * c)
print(f"\nOR(NRD vs no-NRD): {or_value:.2f}")예상 결과:
- NRD = 0: ~30% 취소
- NRD = 1: ~80% 취소
- OR ≈ 9 (Buisson 의 실제 데이터에서는 ~51)
이 OR 이 진짜 인과 효과 (NRD 가 취소를 ~9배 증가시킴) 일까?
답: 아니다. trip_risk 가 confounder 로 양쪽에 영향을 줘서 가짜 양의 상관 발생.
→ 다음 단계에서 trip_risk 를 통제하는 회귀 적합.
5.2 단순 vs Confounder 통제 회귀
import statsmodels.api as sm
# 단순 회귀
X1 = sm.add_constant(df["NRDeposit"])
m1 = sm.Logit(df["IsCanceled"], X1).fit(disp=False)
print(f"=== 단순 회귀: IsCanceled ~ NRD ===")
print(f" beta = {m1.params['NRDeposit']:.3f}")
print(f" OR = {np.exp(m1.params['NRDeposit']):.2f}")
# Confounder 통제
X2 = sm.add_constant(df[["NRDeposit", "trip_risk"]])
m2 = sm.Logit(df["IsCanceled"], X2).fit(disp=False)
print(f"\n=== Confounder 통제: IsCanceled ~ NRD + TripRisk ===")
print(f" beta_NRD = {m2.params['NRDeposit']:.3f}")
print(f" OR_NRD = {np.exp(m2.params['NRDeposit']):.2f}")
print(f" beta_risk = {m2.params['trip_risk']:.3f}")예상 결과:
- 단순 회귀: OR ≈ 9
- Confounder 통제: OR ≈ 1 (또는 작은 양수)
trip_risk 가 회귀에 포함되면 NRD 의 OR 이 1 가까이 떨어짐 — 진짜 인과 효과 ~ 0 에 가까움.
이게 confounder 통제의 위력. 그러나 현실에서는 trip_risk 가 미관측. 우리가 가지고 있는 변수 (PrevCancel, Country, MarketSegment 등) 로 부분 통제만 가능.
→ 잔여 confounding 이 항상 남음. 결과 해석 시 명시.
5.3 변수 brainstorm 자동화
def brainstorm_candidates(treatment, outcome, df):
"""6 카테고리에서 후보 변수 자동 식별 (휴리스틱)."""
candidates = {
"Past Actions": [],
"Intentions": [],
"Cognition": [],
"Personal": [],
"Business": [],
"Time Trends": [],
}
keywords = {
"Past Actions": ["previous", "prior", "history", "past", "repeated"],
"Intentions": ["reason", "purpose", "goal"],
"Cognition": ["awareness", "knowledge", "intent"],
"Personal": ["age", "gender", "country", "income"],
"Business": ["channel", "segment", "type", "category"],
"Time Trends": ["year", "quarter", "month", "season", "date"],
}
for col in df.columns:
if col in [treatment, outcome]:
continue
col_lower = col.lower()
for cat, kws in keywords.items():
if any(kw in col_lower for kw in kws):
candidates[cat].append(col)
break
return candidates
# 예시 사용
print("\n=== 후보 변수 brainstorm ===")
candidates = brainstorm_candidates("NRDeposit", "IsCanceled", df)
for cat, vars_ in candidates.items():
print(f" {cat}: {vars_ if vars_ else '없음 (직관으로 보강)'}")이 도구는 변수 이름 으로 카테고리를 추측. 실제 분석에서는 부족.
이유:
- 변수 이름이 의미를 정확히 반영 안 함 (예:
seg_type이 무엇 의미?) - 미관측 변수는 데이터에 없으므로 자동으로 식별 안 됨
- 카테고리 분류가 도메인 의존적
→ 자동화는 시작점 일 뿐. 분석가의 도메인 직관으로 보강 필수.
6 관련 주제
6.1 Ch.4 의 형제 글
- E-BUI4-0 DAG 0부터 짓기 overview — 4 단계 레시피 전체 흐름
- E-BUI4-2 변수 6 범주 분류 — 6 카테고리 자세히
- E-BUI4-3 데이터 검증과 반복 정제 — 단계 2~3
6.2 이전 챕터
- E-BUI2-1 인간 행동 5 구성요소 — 5 카테고리 도입
- E-BUI2-3 행동적 무결성 마인드셋 — 변수 검증 자세
6.3 후속 챕터
- E-BUI5-0 Deconfounding overview — Ch.5: confounder 식별의 형식적 절차
6.4 Hernan 정통 cross-link
- Causal_Inference/07 교란 — Confounding 의 학술적 정의
- Causal_Inference/04 관찰 연구와 식별 조건 — Confounder 통제의 식별성
6.5 카테고리 진입점
- Experimentation 학습 로드맵 — 11 Phase × 7 교재 매핑