1 정의
데이터의 모든 변수에 대해 “이 변수가 측정한다고 주장하는 행동을 정말 측정하는가” 를 의심하고, 데이터·외부 소스·도메인 지식으로 검증하는 분석 자세 (Buisson, 2021, Ch.2).
핵심 명제는 단순하다: 유죄 증명 전까지 모든 변수를 의심한다.
분석가는 두 자세 중 하나를 선택할 수 있다.
| 자세 A — 신뢰 우선 | 자세 B — 의심 우선 |
|---|---|
| 변수 이름·정의를 액면 그대로 받아들임 | 변수의 데이터 생성 과정·기록 시점 의심 |
| 빠른 분석 가능 | 분석 전 1~2주 변수 점검 |
| 결과 발표 후 “왜 그랬지” 발견 — burning down | 결과 발표 시 confidence 높음 |
| 비즈니스 결정 후 부메랑 위험 | 비즈니스 결정의 ROI 안정 |
자세 A 는 단기 효율에서 이긴다. 자세 B 는 장기 신뢰에서 이긴다.
→ Behavioral Integrity Mindset = 자세 B 의 체화.
2 개념 및 원리 — 7 가지 변수 함정 패턴
Buisson 이 제시한 변수 함정을 7 패턴으로 일반화한다.
2.1 함정 1: Default Assignment (기본값 할당)
“user 1234 의
marketing_consent가TRUE로 기록됨.”
함정 가능성: - 사용자가 아무 응답 안 했고 시스템이 default 로 TRUE 처리 - 사용자가 폼의 다른 필드만 채우고 동의 박스를 안 건드림 - “마케팅 수신 거부” 가 default 로 unchecked → 미응답 = 동의 처리
검증 방법:
- 회원가입 폼의 default 상태 확인 — checked? unchecked?
- 사용자 명시적 클릭 이벤트 로그 추적 — 진짜로 box 를 클릭했는가?
- A/B 테스트로 default 변경 → 동의율 차이 측정 → default 효과 정량화
독일 (opt-in default) 과 오스트리아 (opt-out default) 의 87% 차이가 default 효과의 극단 사례. 비즈니스 데이터에서도 같은 메커니즘이 작동:
- 쿠키 동의 default → “동의” 비율이 default 에 강하게 의존
- 유료 멤버십 자동 갱신 default → 갱신율의 큰 부분이 default 효과
marketing_consent = TRUE 100% 가 default 효과면, “고객 관심” 으로 해석하면 잘못이다.
2.2 함정 2: Fine Print Consent (눈에 안 보이는 동의)
폼 어딘가에 작은 글씨로 “By submitting, you agree to receive marketing emails.”
함정:
- 사용자가 약관을 안 읽고 통과
- 변수
agreed_to_marketing = TRUE로 기록 - 진짜 동의 의도와 무관
검증 방법:
- 약관 문구의 폰트 크기·색·위치 점검
- A/B 테스트로 약관 표시 방식 변경 → 동의 후 행동 (이메일 열람률) 변화 측정
- 동의 후 unsubscribe 비율 추적 — 진짜 동의면 낮음
2.3 함정 3: Self-Reported (자기 보고)
설문 “지난 주에 운동했나요?” → 60% “예”
함정:
- Introspection illusion (자기 인식의 부정확)
- Social desirability bias (사회적 바람직성 — 운동 안 한 게 부끄러워서 거짓 응답)
- Recency bias (최근 1회만 기억하고 “한 주 내내 했다” 답변)
검증 방법:
- 자기 보고 + 실제 행동 측정 (피트니스 트래커·gym 출입 데이터) 의 cross-check
- 일관성 점검: 같은 질문 다른 표현으로 반복 → 응답 변동 측정
심리학 고전 연구. 참가자에게 동일한 양말 4개를 줄지어 놓고 “어느 것이 가장 좋은가” 묻는다. 73% 가 가장 오른쪽 양말 선택.
연구자: “왜 골랐어요?”
참가자들: “재질이 좋아서요”, “색이 좋아서요”, “두께가 좋아서요” — 다양한 합리화. 진짜 이유 (위치 효과) 를 답한 사람 0명.
→ 사람들은 자기 행동의 진짜 원인을 모른 채 자신감 있게 합리화한다. 자기 보고 데이터의 근본적 한계.
2.4 함정 4: External Purchased (외부 구매 데이터)
벤더에서 데이터 구매. “이 사용자는 럭셔리 자동차에 관심” 같은 라벨.
함정:
- 라벨의 정의 불명 (“관심” 의 측정 시점·방법 모름)
- 데이터 신선도 — 1년 전 행동 기반?
- 다른 ID 매칭 정확도 (벤더의 user 와 우리 user 가 같은가)
- 벤더의 모형 가정·편향 미공개
검증 방법:
- 벤더 라벨과 자체 행동 데이터의 일관성 점검
- 작은 표본에서 라벨 검증 (manual review)
- 라벨 사용 전 limitations 명시 (분석 보고서에)
2.5 함정 5: Intent vs Action (의도 vs 행동)
변수 이름: purchased_subscription = TRUE
함정:
- “buy now” 버튼 클릭 (Intent) 만 있고 결제 미완료
- 결제 페이지에서 fail (카드 거부) 후 retry — 단일 trial 인지 multi 인지 모호
- 환불 → 결국 매출 0 인데
purchased = TRUE그대로
검증 방법:
- “구매” 의 정의 정확히: 의도? 첫 결제? 환불 제외 최종? 1년 유지?
- 의도와 실제 결제 사이 funnel 분석
- 환불·취소 후 변수 업데이트 정책 점검
2.6 함정 6: Repeated Action (반복된 단일 행동)
button_click_count = 4 — 사용자가 정말 4번 의도적 클릭?
함정:
- 페이지가 새로고침 안 돼서 4번 연속 클릭 (단일 의도 → 4 행동)
- 더블클릭 습관 (2 클릭이 의도 1)
- 봇·매크로 (대량 자동 클릭)
검증 방법:
- 클릭 간격 분석 — 0.5초 미만은 의도적 클릭 아님 가능
- 클라이언트 idempotency 처리 — 짧은 시간 내 중복 무시
- 사용자별 클릭 패턴 분포 검사 — outlier 식별
2.7 함정 7: Delayed Logging (지연 기록)
event_timestamp = "2026-05-08 14:00" — 이 시점에 이벤트가 발생?
함정:
- 사용자가 5월 1일에 행동 → 시스템이 5월 8일 batch processing → 5월 8일로 기록
- 모바일 앱에서 오프라인 행동 → 온라인 복귀 후 동기화 시점 기록
- 규제 (GDPR 등) 로 인해 일정 시점 이전 데이터는 “오늘” 로 일괄 기록
검증 방법:
- 이벤트 발생 timestamp 와 기록 timestamp 분리 추적 (event_time vs ingest_time)
- 시간대별 이벤트 분포 점검 — 비정상 spike 가 batch 의 흔적일 수 있음
- 규제 정책으로 인한 변동 문서화
다음 두 분석은 같은 데이터에서 정반대 결론을 낼 수 있다.
| 분석 A | 분석 B |
|---|---|
| event_time 사용 | ingest_time 사용 |
| 5월 1일에 행동 발생, 영향 전파 7일 | 5월 8일에 행동 발생, 영향 즉시 |
| “캠페인이 즉시 효과” | “캠페인이 7일 지연 효과” |
같은 데이터, 다른 결론, 다른 비즈니스 의사결정. 시간 함정의 위험은 작지 않다.
3 Distrust and Verify 의 적용 — AirCnC 사례
비즈니스 문제 (반복):
“CSAT 가 향후 6개월 지출 (M6Spend) 에 미치는 효과는?”
3.1 CSAT 점검
| 함정 | AirCnC 의 가능성 | 검증 |
|---|---|---|
| Default | 무응답 → 5점 default? 아닌 경우 점수 높게 가정? | 응답률 + 무응답 처리 정책 확인 |
| Fine print | 평가 기준이 명확한가 (“전반적 만족도”의 정의) | 설문 문구 점검 |
| Self-reported | 매우 강함 — CSAT 자체가 자기 보고 | 행동 (재예약·추천) 과 cross-check |
| External | 외부 평가 사이트 (Trustpilot 등) 의 데이터 사용? | 자체 vs 외부 일관성 |
| Intent vs Action | “만족했다고 답함” vs “정말 만족” | 행동 일관성 (재예약) 으로 검증 |
| Repeated | 같은 사용자 여러 번 평가 시 평균? 최신? | 처리 정책 명시 |
| Delayed | 평가 시점 (예약 직후 vs 일주일 후) 의 차이 | timestamp 분리 추적 |
→ 가장 큰 위험: self-reported. CSAT 만으로 “만족” 결론 짓지 말고 행동 데이터와 통합한다.
3.2 M6Spend 점검
| 함정 | 가능성 | 검증 |
|---|---|---|
| Default | 미사용 사용자 → 0 처리? null? | 처리 정책 확인 |
| Intent vs Action | “예약” vs “결제 완료” vs “취소 후 환불 제외” | 정확한 정의 |
| Repeated | 한 예약을 여러 번 cancel/reorder | dedup 로직 |
| Delayed | 환불은 30일 후 — M6 안에 환불된 건 포함? | 시점별 정의 |
→ 두 변수의 정의를 명확히 하지 않으면 분석 결과의 의미가 흔들린다.
4 왜 필요한가 — 분석 신뢰의 비대칭성
| 시나리오 | 결과 |
|---|---|
| 변수 점검 후 분석 → “효과 있음” | 비즈니스 의사결정 + 결과 검증 → 신뢰 ↑ |
| 변수 점검 후 분석 → “효과 없음” | 의사결정 회피 — 손실 없음 |
| 변수 점검 안 함 → “효과 있음” | 의사결정 후 부메랑 — 큰 손실 |
| 변수 점검 안 함 → “효과 없음” | 진짜 효과 놓침 — 기회 손실 |
→ 분석가의 “조심성” 은 점검 시간 대비 ROI 가 매우 높다. 점검 안 한 비용 이 분석 시간의 10~100배.
4.1 분석 시작 전 체크리스트
분석을 시작하기 전 변수마다 다음 7 질문을 묻는다.
[1] Default — 사용자 응답 없을 때 어떻게 처리?
[2] Fine print — 동의·기준이 명확한가?
[3] Self-reported — 자기 보고? 행동과 cross-check 됐나?
[4] External — 외부 데이터? 정의·신선도 검증?
[5] Intent vs Action — 정확히 어느 단계 측정?
[6] Repeated — 단일 의도의 반복인가, 다중 의도인가?
[7] Delayed — event_time vs ingest_time 차이?
각 질문에 명확한 답이 없으면 → 사용 전 도메인 전문가에게 확인.
5 응용 분야 — 도메인별 가장 자주 발생하는 함정
| 도메인 | 가장 흔한 함정 | 사례 |
|---|---|---|
| 이커머스 | Intent vs Action | 장바구니 추가 ≠ 구매 |
| 구독 | Default + Delayed | 자동 갱신, 환불 처리 시점 |
| 광고 | External (벤더) | “관심사” 라벨의 정의·신선도 |
| HR | Self-reported | 평가 점수의 매니저 주관 |
| 헬스케어 | Self-reported + Recency | “지난주 운동” 응답 |
| 금융 | Delayed | 거래 처리 시점 vs 기록 시점 |
| 모바일 앱 | Delayed (offline sync) | 비행기 모드 후 동기화 |
각 도메인은 자기 함정에 익숙해져야 한다.
- 이커머스 분석가: funnel 의 모든 단계를 분리 (impression / click / cart / checkout / pay / refund)
- HR 분석가: 평가 점수와 객관 KPI (매출·코드 commits·고객 피드백) 의 매트릭스 점검
- 모바일 앱 분석가: event_time + ingest_time + sync_time 3 timestamp 분리 기록
6 예시 — 변수 점검의 실무 다큐멘테이션
좋은 분석 보고서는 다음 섹션을 포함한다.
## 변수 정의 및 점검
### CSAT (Cognition·Emotion)
- 정의: 예약 후 발송된 설문에서 1~10 점 자기 보고
- 응답률: 22%
- 점검 결과:
- [Self-reported] 행동 데이터 (재예약률) 와 상관 r=0.35 — 약한 일관성
- [Delayed] 예약 후 7일 시점 평균 응답 — 즉시 응답 (1일 내) 대비 평균 0.4 점 낮음
- 한계 명시: 응답 편향 (만족한 사용자가 더 많이 응답) — 결과 해석 시 주의
이 섹션이 없으면 분석 결과의 신뢰도가 평가될 수 없다.
7 코드 예시 — Distrust and Verify 자동화 도구
import pandas as pd
import numpy as np
from typing import Dict, List
class VariableAuditor:
"""7 함정 자동 점검."""
def __init__(self, df: pd.DataFrame):
self.df = df
self.audit_results: Dict[str, List[str]] = {}
def audit(self, var: str) -> List[str]:
flags = []
# 1. Default 의심: 한 값이 90% 이상 차지
value_counts = self.df[var].value_counts(normalize=True, dropna=False)
if not value_counts.empty and value_counts.iloc[0] > 0.9:
flags.append(
f"[Default 의심] '{value_counts.index[0]}' 가 "
f"{value_counts.iloc[0]:.0%} — default 처리 가능성"
)
# 2. NaN 의 처리 정책 점검
nan_pct = self.df[var].isna().mean()
if nan_pct > 0.05:
flags.append(
f"[Default 의심] NaN {nan_pct:.0%} — 결측 처리 정책 확인 필요"
)
# 3. Self-reported (수치형) — outlier 분포
if pd.api.types.is_numeric_dtype(self.df[var]):
std = self.df[var].std()
mean = self.df[var].mean()
if std > 0:
outlier_pct = (
(self.df[var] - mean).abs() > 3 * std
).mean()
if outlier_pct > 0.01:
flags.append(
f"[Outlier] {outlier_pct:.1%} 가 3σ 밖 — "
f"이상 응답 또는 측정 오류 의심"
)
# 4. Repeated — 동일 user 의 다중 record
if "user_id" in self.df.columns:
dup_users = (
self.df.groupby("user_id")[var].count() > 1
).sum()
if dup_users > 0:
flags.append(
f"[Repeated] {dup_users} user 가 다중 record — "
f"단일 의도의 반복인지 점검"
)
# 5. Delayed — timestamp 컬럼이 있는 경우
ts_cols = [c for c in self.df.columns if "time" in c.lower() or "date" in c.lower()]
if len(ts_cols) >= 2:
flags.append(
f"[Delayed 점검 필요] timestamp 컬럼 {len(ts_cols)} 개 — "
f"event_time vs ingest_time 차이 점검"
)
self.audit_results[var] = flags
return flags
def report(self) -> pd.DataFrame:
"""점검 결과를 DataFrame 으로."""
rows = []
for var, flags in self.audit_results.items():
for flag in flags:
rows.append({"변수": var, "발견": flag})
return pd.DataFrame(rows)
# 가상 AirCnC 데이터 점검
np.random.seed(42)
df = pd.DataFrame({
"user_id": np.random.choice(range(100), 500),
"csat_score": np.random.choice([5, 6, 7, 8, 9, 10], 500, p=[0.05, 0.05, 0.1, 0.2, 0.3, 0.3]),
"marketing_consent": np.random.choice(
[True, False], 500, p=[0.95, 0.05] # 95% TRUE — default 의심
),
"event_time": pd.to_datetime("2026-05-01") + pd.to_timedelta(np.random.randint(0, 7*24*60, 500), unit="m"),
"ingest_time": pd.to_datetime("2026-05-08"), # 모두 같은 시점 — delayed 의심
})
auditor = VariableAuditor(df)
for var in ["csat_score", "marketing_consent"]:
print(f"\n=== {var} 점검 ===")
flags = auditor.audit(var)
for f in flags:
print(f" - {f}")
print("\n\n=== 요약 ===")
print(auditor.report())이 도구는 휴리스틱 1차 필터다. 실제 함정은 비즈니스 컨텍스트를 알아야 발견된다.
- “marketing_consent 가 95% TRUE” 가 자동 발견됨 — 그런데 이게 진짜 default 효과인지, 아니면 진짜로 95% 가 동의했는지는 컨텍스트 (회원가입 폼 디자인) 점검 필요.
- “event_time 과 ingest_time 분리 컬럼 존재” 자동 발견 — 두 시점 차이의 비즈니스 의미는 도메인 전문가에게.
→ 자동 점검 + 사람의 도메인 지식이 결합되어야 한다. 자동 도구만으로는 60% 정도, 사람만으로는 40% 정도 — 둘 결합 시 90% 이상 함정 발견 가능.
8 코드 예시 — AirCnC CSAT vs M6Spend 의 변수 일관성 점검
def consistency_check(df, csat_col, action_col):
"""CSAT (자기 보고) vs Action 의 일관성 점검."""
# 분기별로 CSAT 점수와 행동 비율 비교
csat_quartile = pd.qcut(df[csat_col], q=4, labels=["Q1", "Q2", "Q3", "Q4"])
action_by_quartile = df.groupby(csat_quartile, observed=True)[action_col].mean()
print(f"CSAT 분위별 {action_col} 비율:")
print(action_by_quartile)
# CSAT 가 높을수록 action 비율이 단조 증가해야 일관
if action_by_quartile.is_monotonic_increasing:
print("→ 단조 증가 — CSAT 와 행동 일관성 양호")
else:
print("→ 단조 증가 아님 — CSAT 자기 보고와 실제 행동 불일치 가능")
print(" 추가 점검 필요: introspection illusion? 응답 편향?")
# 가상 데이터로 점검
np.random.seed(42)
df_check = pd.DataFrame({
"user_id": range(1000),
"csat_score": np.random.choice([5, 6, 7, 8, 9, 10], 1000),
"actual_rebooked": np.random.binomial(1, 0.4, 1000),
})
# CSAT 와 rebooked 약하게 상관 만들기
df_check["actual_rebooked"] = (
np.random.binomial(1, 0.2 + 0.05 * (df_check["csat_score"] - 5), 1000)
)
consistency_check(df_check, "csat_score", "actual_rebooked")만약 결과가:
- 단조 증가 (CSAT Q1: 0.20 → Q4: 0.45) → 좋은 신호. CSAT 가 행동을 예측.
- 비단조 (CSAT Q1: 0.30, Q2: 0.25, Q3: 0.40, Q4: 0.35) → CSAT 가 행동을 잘 예측 못함.
비단조라면 가능한 해석:
- Self-reported 함정: 만족 점수가 진짜 만족과 안 맞음
- 다른 confounder: CSAT 와 행동 사이 제3의 변수가 있음
- 비선형 관계: 매우 만족한 사람이 오히려 다른 옵션 탐색 (충성도와 다양성 추구의 trade-off)
각 가설을 별도로 검증해야 한다.
9 관련 주제
9.1 Ch.2 의 형제 글
- E-BUI2-0 행동 데이터 이해 overview — Ch.2 전체 흐름
- E-BUI2-1 인간 행동 5 구성요소 — 각 요소 상세
- E-BUI2-2 행동·데이터 연결 — 5요소 매핑 절차 — Behavioralize 절차
9.2 후속 챕터
- E-BUI3-0 인과 다이어그램 도입 — 점검된 변수로 DAG 짓기
- E-BUI4-0 DAG 0부터 짓기 — AirCnC 사례 본격 분석
- E-BUI6-0 결측 데이터 처리 overview — 변수 함정의 통계적 처리
9.3 Hernan 정통 cross-link
- Causal_Inference/09 측정 오차와 랜덤 변동 — 측정 편향의 학술적 처리
- Causal_Inference/03 무작위 실험과 교환가능성 — RCT 가 self-reported 함정을 해결하는 메커니즘
9.4 카테고리 진입점
- Experimentation 학습 로드맵 — 11 Phase × 7 교재 매핑