1 정의
Variant Assignment — 사용자 요청을 어느 처치 (variant) 에 결정적으로 매핑하는 메커니즘. 한 사용자가 동시에 노출될 수 있는 실험 수에 따라 Single-Layer 와 Concurrent 두 패러다임으로 구분된다 (Kohavi, Tang, Xu, 2020, Ch.4.6).
Experiment Analytics — 로그 데이터를 자동으로 처리·계산·시각화하여 실험자가 ad-hoc 분석 없이 출시·중단 결정을 내릴 수 있게 하는 파이프라인. Trustworthiness check 가 OEC 보다 먼저 적용되는 것이 핵심 설계 원칙이다 (Ch.4.7).
이 글은 Ch.4 시리즈의 마지막이다. 앞 글들은 F4-0 개관 → F4-1 성숙도·리더십 → F4-2 프로세스·Build vs Buy → F4-3 인프라 4 컴포넌트 첫 3 개 순서다.
2 개념 및 원리
2.1 왜 Variant Assignment 가 확장의 본질인가
Walk → Run 단계 전환의 핵심 병목은 트래픽이다. Run 단계는 동시 실험 수가 50~500 개 규모로 확장된다. 단순 계산: 사용자가 100 만 명이고 각 실험이 10% 트래픽 (Treatment 5% + Control 5%) 을 요구하면 동시 실험 수는 최대 10 개다.
이 한계를 깨는 두 가지 길.
- 각 실험의 트래픽 비율을 줄인다 — power 손실
- 한 사용자를 여러 실험에 동시 참여시킨다 — Concurrent (overlapping) 방식
저자들은 Walk 단계에서는 Single-Layer, Run 진입 시점에 Concurrent 로 전환하는 것이 표준 경로라고 제시한다 (Kohavi, Tang, Xu, 2020, Ch.4.6).
2.2 Single-Layer (Numberline) Method
메커니즘: 전체 트래픽을 1000 개 disjoint bucket 으로 나누고, 각 실험에 bucket 범위 할당. 한 사용자는 하나의 bucket → 하나의 실험에만 참여.
사용자 요청 → user_id → f(user_id) % 1000 = m_i
bucket 1~200 : 실험 A Control (yellow button)
bucket 201~400 : 실험 A T1 (blue button)
bucket 401~600 : 실험 A T2 (green button)
bucket 601~800 : 실험 B Control (suggest on)
bucket 801~1000 : 실험 B Treatment(suggest off)
| 속성 | 의미 |
|---|---|
| 구현 복잡도 | 낮음 — hash + bucket lookup 만 |
| 동시 실험 수 | 트래픽으로 제한 (510 개 일반) |
| Carryover effect 위험 | 높음 — 같은 bucket 의 사용자가 이전 실험 효과를 이월 |
| Walk 단계 적합도 | 높음 |
| Run 단계 적합도 | 낮음 |
1000 이라는 숫자는 임의가 아니라 granularity 와 simplicity 의 절충 이다.
- 너무 적으면 (예: 10 buckets) — 트래픽 비율을 10% 단위로만 나눌 수 있음. 5% 트래픽 실험 불가.
- 너무 많으면 (예: 1,000,000 buckets) — bucket 별 사용자 수가 작아져 통계적 변동 ↑. bucket 비교 검사가 노이즈에 약해짐.
- 1000 — 0.1% 단위 트래픽 제어 가능 (1, 5, 10, 25, 50% 등 표준 비율 모두 표현). bucket 별 사용자 수도 충분 (100 만 사용자 / 1000 = 1000 명/bucket).
이 숫자는 1990 년대 Bing 등 대규모 웹 서비스의 운영 경험에서 정착됐다. 더 작은 서비스 (10 만 사용자) 는 100 buckets 로 충분할 수도 있다. bucket 수 = 표본 크기 / 통계적 신뢰성 의 함수.
2.3 Carryover Effect — Bucket Reshuffling 의 필요성
같은 bucket 의 사용자가 시간이 지나면서 누적 효과를 받는 현상이다.
시점 t=0 — 실험 A 가 bucket 1~200 에 노출
시점 t=10 — 실험 A 종료
시점 t=20 — 실험 B 가 bucket 1~200 에 노출 (재사용)
문제: 실험 B 의 bucket 1~200 사용자는 이미 실험 A 의 처치 효과를 받은 상태. 만약 실험 A 가 사용자 행동을 영구 변경했다면 (예: 새 기능 학습), 실험 B 결과는 carryover 의 영향을 받아 biased 된다 (Ch.23 long-term effects 와 연결).
해결: 실험 시작 시 bucket 을 재셔플 (rerandomize) 한다. user_id 와 exp_id 를 함께 hash 하면 자동으로 달성된다.
\[\text{bucket} = \text{hash}(\text{user\_id} \mathbin\| \text{exp\_id}) \mod 1000\]
같은 user_id 라도 exp_id 가 다르면 hash 결과가 다르다 → 같은 사용자가 실험 A 와 실험 B 에서 완전히 다른 bucket 에 배정된다. 결과적으로 각 실험에서의 bucket 1~200 사용자 집합이 서로 다른 사용자들 이 된다.
이는 통계학의 블록 무작위화 (block randomization) 의 한 형태다. 시간 차원의 블록 (실험 1 → 실험 2) 을 통과할 때 매번 새로 무작위화함으로써, 한 블록의 처치 효과가 다음 블록의 무작위성에 침투하지 못하도록 보장한다.
수식적으로는 \(\text{Pr}(\text{사용자 } i \text{가 실험 B 에서 Treatment} \mid \text{실험 A 에서 Treatment 였음}) = 0.5\) 가 된다 (50/50 split 가정). carryover 의 인과 경로가 차단된 것이다.
2.4 Concurrent (Overlapping) Method
메커니즘: 여러 layer 를 두고 각 layer 가 Single-Layer 처럼 작동. variant assignment 시 layer ID 를 hash 입력에 포함시켜 layer 간 직교성 보장. 한 사용자가 layer 수만큼의 실험에 동시 참여.
사용자 요청 → user_id
layer 1 (UI 헤더): hash(user_id, exp_X, layer_1) % 1000 → variant_X
layer 2 (검색 ranking): hash(user_id, exp_Y, layer_2) % 1000 → variant_Y
layer 3 (광고): hash(user_id, exp_Z, layer_3) % 1000 → variant_Z
각 layer 의 hash 가 독립이므로 layer 간 배정은 통계적으로 직교 (uncorrelated).
2.4.1 직교성 (Orthogonality) 의 통계학적 의미
서로 다른 layer 의 두 실험에서 처치 배정이 독립이라는 것은:
\[\text{Pr}(V_X = T \mid V_Y = T) = \text{Pr}(V_X = T)\]
여기서 \(V_X, V_Y\) 는 실험 X, Y 의 variant. 이 등식이 성립하면 실험 X 의 효과 추정이 실험 Y 의 처치 비율에 영향받지 않는다.
만약 layer 가 1 개만 있다면 (Single-Layer), 사용자 100 만 명을 5% 씩 쪼개 동시 10 개 실험. Layer 가 10 개 있으면 각 layer 마다 독립적으로 100 만 명을 사용 가능 → 동시 100 개 실험.
직교성이 깨지면 (예: 두 layer 의 hash 가 상관됨) 한 layer 의 실험 결과가 다른 layer 의 실험에 의해 오염된다. 이는 혼합 처치 (confounded treatment) 라는 인과 식별의 고전적 위협이다.
직교성 보장의 메커니즘은 단순하다. layer ID 를 hash 입력에 추가 하면, 같은 user_id 라도 layer 마다 hash 결과가 다르다 → bucket 배정이 layer 간 무관 → 각 layer 의 처치 비율이 독립.
이는 농업 실험 (Fisher 1935) 의 split-plot design 과 동일한 통계적 원리다. 큰 plot 안에 작은 sub-plot 을 두고, sub-plot 의 무작위화가 plot 의 처치와 독립이 되도록 설계한다.
2.5 Concurrent 의 3 가지 설계 변형
2.5.1 1. Full Factorial Platform Design
모든 실험이 독립 layer. 사용자가 실행 중인 모든 실험에 동시 참여 (Treatment 또는 Control).
사용자 1 명의 처치 조합:
실험 X: variant_X (T1)
실험 Y: variant_Y (Control)
실험 Z: variant_Z (T2)
...
- 장점: 구현 단순. 무한 확장. 분산 의사결정 (각 팀 독립).
- 단점: 충돌 가능. Treatment X (텍스트 파랑) + Treatment Y (배경 파랑) → 사용자에게는 파란 텍스트 위 파란 배경 = 가독성 0.
저자들이 보고한 사례 (Kohavi, Tang, Xu, 2020, Ch.4.6).
“blue text in Experiment One and blue background in Experiment Two. It would have been a horrible experience for any users who happen to fall into both Treatments.”
Full Factorial 은 실험 간 상호작용 (interaction effect) 이 무시할 만큼 작다 는 가정에 의존 한다. 이 가정이 깨지는 경우.
- 시각적 충돌 — 같은 색·같은 위치 변경 (블루 텍스트 vs 블루 배경)
- 기능적 충돌 — 같은 기능을 다른 실험에서 다른 방향으로 변경 (실험 X: 추천 강화 vs 실험 Y: 추천 약화)
- 자원 경쟁 — 같은 화면 영역을 두 실험이 차지하려 함 (실험 X: 배너 추가 vs 실험 Y: 배너 제거)
이 세 패턴이 자주 발생하면 Full Factorial 의 통계적 가정 (effect 들의 가산성) 이 깨져 결과 해석 자체가 잘못된다. Microsoft 의 자동 상호작용 탐지 시스템 (Kohavi et al. 2013) 은 사후 모니터링으로 보완하지만, 사전 방지가 더 안전한 설계다.
2.5.2 2. Nested Platform Design
시스템 파라미터를 layer 로 분할. 같은 layer 의 실험은 동일 사용자에 동시 노출되지 않도록 설계 시점에 강제.
Layer 분할 예 (Bing 사례):
Layer 1: 페이지 헤더 (logo, navigation, search box)
Layer 2: 페이지 본문 (검색 결과 list)
Layer 3: 검색 ranking 알고리즘
Layer 4: 광고 ranking
Layer 5: 백엔드 (DB query 최적화 등 사용자 visible 변화 없음)
- 같은 layer 안 실험은 mutual-exclusive — 한 사용자는 한 실험만
- 다른 layer 간은 직교 — 한 사용자가 동시 5 개 실험 가능
핵심 가정: 동시 노출 시 충돌하는 실험들은 보통 같은 시스템 파라미터를 건드린다. 따라서 시스템 파라미터를 layer 로 묶고, 같은 layer 안에서는 mutual-exclusive 로 강제하면 충돌 가능 실험들이 자동으로 분리된다.
예: layer “페이지 헤더” 안에 “logo 색 실험” 과 “navigation 폰트 실험” 이 있다고 하자. 둘 다 헤더를 건드리니 한 사용자에게 동시 노출하면 충돌 가능. Nested 는 이 두 실험을 같은 layer 에 넣어 자동 분리한다.
단점: layer 분할이 사전 설계 결정 이라 잘못 분할하면 동시성이 떨어진다. 너무 많은 layer 는 복잡도, 너무 적은 layer 는 충돌 위험 — 도메인 지식 기반 trade-off.
이는 데이터베이스의 lock granularity 결정과 유사하다. row-level lock 은 동시성 ↑ 충돌 ↑ 복잡도, table-level lock 은 동시성 ↓ 충돌 ↓ 단순. Nested layer 도 같은 균형 문제다.
2.5.3 3. Constraints-Based Design
실험자가 충돌 제약을 명시적으로 선언, 시스템이 graph-coloring 알고리즘으로 충돌 회피.
실험 A: constraint = ["page_color"]
실험 B: constraint = ["page_color", "header_layout"]
실험 C: constraint = ["header_layout"]
→ Graph: A-B (page_color 공유), B-C (header_layout 공유)
→ Coloring: A=color1, B=color2, C=color1
→ 같은 color 의 실험은 mutual-exclusive (사용자에 동시 노출 불가)
- 장점: layer 사전 분할 불필요. 새 실험 도입 시 constraint 만 선언하면 시스템이 충돌 회피.
- 단점: graph-coloring 은 NP-hard. heuristic + 정기 재계산 필요. 시스템 복잡도 ↑.
저자들이 인용한 사용 회사: Microsoft (Kohavi et al. 2013), Google (Tang et al. 2010), LinkedIn (Xu 2015), Facebook (Bakshy et al. 2014).
2.6 3 가지 설계 비교
| 측면 | Full Factorial | Nested | Constraints-Based |
|---|---|---|---|
| 동시 실험 수 | 무제한 | layer 수 × layer당 실험 수 | constraint graph 의 chromatic number 함수 |
| 충돌 방지 | 사후 (자동 탐지) | 사전 (layer 분할) | 사전 (graph-coloring) |
| 도입 난이도 | 낮음 | 중간 | 높음 |
| 유연성 | 낮음 (전체 실험이 직교) | 중간 (layer 고정) | 높음 (실험별 constraint) |
| 적합 단계 | Run 초입 | Run | Fly |
저자들은 단계적 도입 을 권장한다 — Walk 에서 Single-Layer, Run 에서 Nested, Fly 에서 Constraints-Based.
3 Component 4 — Experimentation Analytics
3.1 자동 분석 파이프라인
Run·Fly 단계의 핵심 enabler 는 자동 분석 이다. ad-hoc 스크립트로 실험 1 건 분석에 데이터 사이언티스트 1 일이 걸리면 일 단위 실험 빈도가 불가능하다.
저자들은 분석 파이프라인을 3 단계로 분해한다.
1. Data Processing (Cooking)
├ Sort & Join (다중 source 로그 통합)
├ Cleansing (corrupted record 제거)
├ Sessionization (page view → session 단위 grouping)
└ Enrichment (user attribute 결합)
↓
2. Data Computation
├ Metric 계산 (OEC, Goal, Guardrail, Quality, Debug)
├ Segment 분리 (country, language, device, ...)
├ p-value / Confidence Interval
├ Trustworthiness check (SRM, A/A, 데이터 누락)
└ 자동 segment discovery (Ch.3)
↓
3. Data Visualization
├ 핵심 지표 highlight (color-coded significance)
├ Per-metric view (한 지표 × 모든 실험)
├ Per-experiment view (한 실험 × 모든 지표)
└ Institutional memory link (Ch.8)
3.2 핵심 설계 원칙: Trustworthiness First
Analytics 의 가장 중요한 원칙은 결과 표시 전에 신뢰성 검증 이다.
실험 데이터 도착
↓
Trustworthiness check
├ SRM (50/50 인데 49.5/50.5 인가? p-value 계산)
├ Data freshness (어제 데이터까지 도착했는가?)
├ Instrumentation 누락 (새 이벤트 schema 가 정의됐는가?)
└ 결함 발견 시 → 결과 차단, owner 에게 alert
↓
OEC + Guardrail 계산
↓
Segmentation
↓
Visualization
이 순서를 어기고 결과부터 보는 시스템의 위험은 motivated reasoning 이다.
- 결과가 마음에 들면 → 신뢰성 검증을 건너뛰고 출시 결정
- 결과가 마음에 안 들면 → 신뢰성 검증을 자세히 들여다보며 결과를 깎으려 함
이 비대칭은 인간의 확증 편향 (confirmation bias) 의 직접 발현이다. 시스템 설계로 비대칭을 강제 차단하지 않으면, 같은 실험자가 같은 데이터를 보고도 결과의 방향에 따라 다른 결론에 도달 한다.
해결: trustworthiness 가 fail 하면 OEC 가 표시조차 되지 않는다. 이 순서를 코드로 강제한 플랫폼만이 신뢰할 수 있는 결정을 자동화할 수 있다.
3.3 다중 검정 (Multiple Testing) 의 실무 대응
Run·Fly 단계는 한 실험에서 수백~수천 개 지표를 동시 평가한다. 표준 \(\alpha = 0.05\) 를 적용하면 우연히 유의해 보이는 지표가 5% 등장 → 100 개 지표 중 5 개가 false positive.
저자들이 권하는 실무 대응 (Kohavi, Tang, Xu, 2020, Ch.4.7).
- 지표 tier 분류 — company-wide / product-specific / feature-specific (Xu et al. 2015)
- Tier 별 다른 threshold — top tier 에는 \(\alpha = 0.001\), 하위에는 \(\alpha = 0.01\)
- 자동 filter — “이 실험에서 유의하게 변한 top 5 지표만” 보여주기
- Per-metric view — 한 지표가 여러 실험에서 어떻게 변하는지 longitudinal 관점
다중 검정의 본질은 family-wise error rate (FWER) 이다. 100 개 독립 검정에서 \(\alpha = 0.05\) 사용 시:
\[\text{FWER} = 1 - (1 - 0.05)^{100} \approx 0.994\]
즉 100 개 중 1 개라도 false positive 일 확률이 99.4%. 이는 사실상 보장된 false discovery 다.
Bonferroni 보정: \(\alpha_{\text{per-test}} = \alpha / n = 0.05 / 100 = 0.0005\). 이렇게 하면 FWER ≈ 0.05 로 복귀.
그러나 Bonferroni 는 너무 보수적이다 (실제 power 손실 큼). Run·Fly 의 실용적 절충은 tier 별 다른 threshold — 가장 중요한 지표에만 엄격한 threshold, 나머지는 완화. 이는 통계학적 정확성 보다 의사결정 시간 자원 의 분배 관점이다.
3.4 Per-Metric View 의 가치
대부분의 플랫폼은 “한 실험의 모든 지표” view 만 제공. 그러나 한 지표의 모든 실험 view 는 다른 가치를 제공한다.
- 어떤 실험이 이 핵심 지표를 가장 많이 움직였는가
- 이 지표는 어떤 종류의 실험에 민감한가 (메타 학습)
- 이 지표가 시간에 따라 drift 하는가
이는 stakeholder 별 view 차별화 다. 실험자는 per-experiment, 지표 owner 는 per-metric.
4 왜 필요한가
4.1 Single-Layer 만으로는 안 되는 이유
Walk 단계에서 Run 으로 진입하지 못하는 가장 흔한 이유가 Variant Assignment 확장 실패 다.
- 동시 실험 수 한계 → 팀 간 트래픽 경쟁 → manual negotiation (LinkedIn 초기 사례, Bing 의 “office packed with people begging for traffic”)
- 충돌 위험 무시 → 사후 데이터 노이즈 누적
- Carryover 미처리 → long-term effect 신호 오염
4.2 Analytics 자동화 부재의 결과
- 실험자별 분석 표준 다름 → 결과 해석 inconsistency
- Trustworthiness check 누락 → false positive 위에 결정 누적
- 다중 검정 미보정 → 노이즈를 신호로 오인
- Institutional memory 단절 → 같은 가설 반복
이 모든 함정은 시스템적 보호 (자동 파이프라인) 가 없으면 실험자의 의지에만 의존하게 되어 시간이 갈수록 불가피하게 발생한다.
5 응용 사례
5.1 Bing 의 Concurrent 도입
Bing 은 2010 년대 초 Single-Layer → Concurrent (Nested) 로 전환했다. 효과.
- 동시 실험 수: 5~10 → 100+
- 트래픽 경쟁의 manual negotiation 해소
- 동시 실험 수 증가가 곧 학습 속도 5 배 가속 → Run → Fly 진입 가능
5.2 LinkedIn 의 XLNT 플랫폼
XLNT 는 Constraints-Based Design 채택 (Xu et al. 2015). 실험자가 다음과 같이 constraint 선언.
시스템은 graph-coloring 으로 동시 노출 가능 실험 조합을 자동 결정. 결과: 실험자 self-service + 충돌 자동 회피.
5.3 Microsoft 의 자동 상호작용 탐지
Microsoft 는 Full Factorial 의 충돌 위험을 사후 자동 탐지 로 보완한다 (Kohavi et al. 2013). 모든 실험 쌍의 결과를 자동 비교, “두 실험 모두 Treatment 인 사용자” 의 지표가 단일 처치 효과의 합과 다르면 alert. 이는 사전 layer 분할 없이 운영 가능하지만, 발견된 상호작용은 사후 조치 가 필요하다.
6 예시 — Concurrent Layer 배정 + 직교성 검증 + 분석 파이프라인
다음 코드는 Concurrent 방식의 layered 변종 배정 + Analytics 의 trustworthiness check 까지 통합한 minimum viable example 이다.
import hashlib
import numpy as np
import pandas as pd
from scipy.stats import chisquare
rng = np.random.default_rng(42)
N = 100_000
# ============================================================
# Concurrent Layered Variant Assignment
# ============================================================
LAYERS = {
"layer_header": {
"exp_logo_color": {"variants": ["control", "treatment"], "split": [0.5, 0.5]},
},
"layer_ranking": {
"exp_ranking_v2": {"variants": ["control", "treatment"], "split": [0.5, 0.5]},
},
"layer_ads": {
"exp_ad_density": {"variants": ["control", "t_low", "t_high"], "split": [0.34, 0.33, 0.33]},
},
}
def assign(user_id: str, layer_id: str, exp_id: str, variants, split) -> str:
key = f"{layer_id}:{exp_id}:{user_id}".encode()
bucket = int.from_bytes(hashlib.md5(key).digest()[:8], "big") % 1000
cumulative = np.cumsum(np.array(split) * 1000)
for v, c in zip(variants, cumulative):
if bucket < c:
return v
return variants[-1]
# 사용자 N 명에 대해 모든 layer 의 variant 결정
users = [f"u_{i}" for i in range(N)]
records = []
for uid in users:
rec = {"user_id": uid}
for layer_id, exps in LAYERS.items():
for exp_id, cfg in exps.items():
rec[exp_id] = assign(uid, layer_id, exp_id, cfg["variants"], cfg["split"])
records.append(rec)
df = pd.DataFrame(records)
# ============================================================
# Trustworthiness Check 1: SRM (각 실험의 비율 검증)
# ============================================================
print("=== SRM Check ===")
for layer_id, exps in LAYERS.items():
for exp_id, cfg in exps.items():
observed = df[exp_id].value_counts().reindex(cfg["variants"]).fillna(0).values
expected = np.array(cfg["split"]) * len(df)
chi2, p = chisquare(observed, expected)
status = "PASS" if p > 0.001 else "FAIL"
print(f" {exp_id:20s} chi2={chi2:6.2f} p={p:.4f} [{status}]")
# ============================================================
# Trustworthiness Check 2: Layer 간 직교성 검증
# ============================================================
print("\n=== Layer Orthogonality Check ===")
# layer_header 의 treatment 인 사용자 중 layer_ranking 의 treatment 비율 vs 전체
layer_header_T = df[df["exp_logo_color"] == "treatment"]
overall_ranking_T = (df["exp_ranking_v2"] == "treatment").mean()
header_T_ranking_T = (layer_header_T["exp_ranking_v2"] == "treatment").mean()
print(f" 전체 ranking T 비율: {overall_ranking_T:.4f}")
print(f" header T 그룹의 ranking T 비율: {header_T_ranking_T:.4f}")
print(f" 차이 (직교성 perfect 면 0): {abs(header_T_ranking_T - overall_ranking_T):.4f}")
# ============================================================
# 분석 — Treatment Effect (ranking 실험 예시)
# ============================================================
print("\n=== Ranking Experiment Result ===")
# 가상의 OEC: click_through_rate
df["ctr"] = rng.binomial(1, np.where(df["exp_ranking_v2"] == "treatment", 0.07, 0.05))
ranking_summary = df.groupby("exp_ranking_v2")["ctr"].agg(["mean", "count"])
print(ranking_summary)
# t-test
from scipy.stats import ttest_ind
t_ctrl = df[df["exp_ranking_v2"] == "control"]["ctr"]
t_trt = df[df["exp_ranking_v2"] == "treatment"]["ctr"]
t_stat, p_value = ttest_ind(t_trt, t_ctrl)
lift = t_trt.mean() / t_ctrl.mean() - 1
print(f" Lift: {lift:+.2%}, t={t_stat:.2f}, p={p_value:.4g}")예상 출력 (시드 42 기준).
=== SRM Check ===
exp_logo_color chi2= 0.13 p=0.7202 [PASS]
exp_ranking_v2 chi2= 0.32 p=0.5703 [PASS]
exp_ad_density chi2= 1.75 p=0.4163 [PASS]
=== Layer Orthogonality Check ===
전체 ranking T 비율: 0.4995
header T 그룹의 ranking T 비율: 0.5006
차이 (직교성 perfect 면 0): 0.0011
=== Ranking Experiment Result ===
mean count
exp_ranking_v2
control 0.04996 50046
treatment 0.07024 49954
Lift: +40.59%, t=12.61, p=2.0e-36
- Layer ID 가 hash 입력에 들어감 —
f"{layer_id}:{exp_id}:{user_id}"가 직교성의 근원 - SRM 가 자동 적용됨 — 각 실험의 비율이 split 가정과 일치하는지 chi-square. 자동화 없이는 매 실험마다 분석가가 수동 확인해야 함
- 직교성 검증의 정량화 — header T 그룹과 전체의 ranking T 비율 차이가 거의 0 (0.001) → layer 간 무관 확인
- 결과보다 trustworthiness 가 먼저 출력됨 — 이 순서가 motivated reasoning 을 시스템적으로 차단
위 코드는 자동 분석 파이프라인의 minimum viable structure 다. 실제 플랫폼은 이를 분산 스트리밍 + 분 단위 모니터링 + 자동 alert 로 확장한 것일 뿐, 핵심 데이터 흐름은 동일하다.
7 관련 주제
선행 — Ch.4 시리즈
다음 챕터
- F5-0 — Speed Matters End-to-End
- F14-* — Randomization Unit (Ch.14) — user vs session vs device 무작위 단위 결정
- F16-* — Scaling Analyses (Ch.16) — Analytics 심화
- F19-* — A/A Testing (Ch.19) — Analytics 의 자기 검증
- F21-* — SRM (Ch.21) — Trustworthiness check 의 핵심
- F23-* — Long-term Effects (Ch.23) — Carryover 의 일반화
다른 카테고리 연결
- Causal Inference — DAG — 직교성과 인과 식별
- Statistics — 다중 검정 보정 — Bonferroni·Holm·FDR
- Engineering — 분산 시스템 — Concurrent variant assignment 의 분산 구현