Time-to-Event Measures: 시간-사건 분석 지표 종합

Incidence Rate·Hazard Ratio·KM·SMR — 시간 정보가 있을 때 RR 의 일반화

Risk·RR 은 사건의 유무만 보지만, 코호트·생존 데이터는 사건이 “언제” 일어나는지가 핵심이다. Incidence Rate (IR), Incidence Rate Ratio (IRR), Hazard Ratio (HR), Kaplan-Meier (KM), log-rank, Cox PH, Standardized Mortality/Incidence Ratio (SMR/SIR), Causal Survival, 메타분석 (pooled HR·I²) 까지 시간-사건 지표를 한 글에 정리한다.

Epidemiology
Experimentation
Causal Inference
저자

Kwangmin Kim

공개

2026년 05월 08일

이 포스트는 effect_measures.qmd 의 시간 일반화다. RR/OR 이 사건의 유무 (이항) 를 보는 반면, 시간-사건 분석은 “사건이 언제 일어나는가” 를 정량화한다. 일부 환자는 추적 종료까지 사건을 겪지 않아 (censoring) 단순 비율로 다룰 수 없다.

1 정의

정의: Time-to-Event Data

각 개체에 대해 (1) 시간 \(T_i\) 와 (2) 관측 종료 시점에 사건이 일어났는지 여부 \(\delta_i \in \{0, 1\}\) 가 함께 관측되는 데이터.

  • 사건 시간 \(T_i\): 처치/노출 시점부터 사건 발생까지의 시간
  • 중도절단 (Censoring) \(\delta_i = 0\): 추적 종료까지 사건이 일어나지 않음 (right censoring)
  • 위험 집단 (Risk Set): 시점 \(t\) 에 아직 사건을 겪지 않고 추적 중인 개체 집합

핵심 도전: 중도절단 데이터에서 평균 사건 시간을 단순 평균으로 추정하면 편향된다 — 사건을 겪지 않은 사람의 정보를 무시할 수 없다.

A/B test 의 retention·churn 분석은 이 프레임워크의 IT 버전 (Kohavi, Tang, Xu, 2020, Ch.4).

직관: 왜 censored 데이터를 무시하면 안 되는가

100 명의 환자를 5 년 추적, 30 명이 사망 (이 중 평균 사망 시간은 2 년), 70 명이 5 년까지 생존. “평균 생존 시간” 을 어떻게 추정할까?

  • Naive 1: 사건 시간만 평균 → 30 명의 평균 = 2 년 → 70 명의 정보 무시. 명백한 과소 추정.
  • Naive 2: 모든 사람의 관측 시간 평균 → (30 × 2 + 70 × 5) / 100 = 4.1 년 → 70 명을 5 년에 사망한 것처럼 취급 (실제로는 그 후에도 살아있을 가능성). 과대 추정.
  • 올바른 답: KM 으로 생존곡선 \(S(t)\) 추정 → 5 년 초과 영역은 비식별 (admin censoring) 로 다루고, 그 시점까지의 생존확률을 보고. 단일 평균 대신 곡선이나 RMST (Restricted Mean Survival Time) 사용.

A/B test 비유: 추천 알고리즘 A vs B 의 retention 비교. 6 개월 추적, 일부 사용자는 마지막 날 가입 (실제로 6 개월 후 어떻게 될지 모름). 단순 churn rate (30 일 내 이탈 / 전체) 는 가입 시점이 다양하면 편향. KM 으로 시간-기반 retention 곡선을 그려야 정직.

2 빈도 지표 — Risk·Rate·Prevalence

같은 데이터라도 분모와 시간 단위에 따라 지표가 달라진다.

2.1 Risk vs Rate vs Odds (재방문)

지표 분자 분모 단위 시간 정보
Risk 사건 수 인구 (한 시점) 비율 (0~1) 없음 (cumulative)
Incidence Rate (IR) 사건 수 person-time 1/시간 필수
Odds 사건 수 비사건 수 비율 (0~∞) 없음
Prevalence 보유자 수 인구 (한 시점) 비율 (0~1) 단면
직관: Risk 와 IR 의 차이
  • 100 명을 1 년 추적, 10 명이 사건을 겪고 90 명이 1 년 내내 추적됨
    • Risk = 10 / 100 = 0.10 (10% 위험)
    • Person-time = 10 × 0.5 + 90 × 1 = 95 person-years (사건 직전 0.5 년 가정)
    • IR = 10 / 95 = 0.105 events/person-year
  • 추적 기간이 짧거나 모든 사람이 끝까지 추적되면 Risk ≈ IR × 시간
  • 중도절단이 많거나 시간이 길면 차이 커짐 — IR 만 안정적

2.2 Incidence Rate (IR) — Person-Time 의 의미

\[ \text{IR} = \frac{\text{새 사건 수}}{\text{Person-time at risk}} \]

person-time = 각 개체의 추적 시간 합. 100 명을 평균 0.95 년 추적하면 95 person-years.

  • 장점: 동적 인구 (입사·퇴사·사망이 있는 코호트) 에서도 안정적 추정 가능
  • 단점: 사건 위험이 시간에 따라 일정 (constant hazard) 이라는 가정 — 위반 시 시간 구간별로 분리 (piecewise constant)
  • 단위: events/person-year, /1000 person-years 등
직관: 1 명을 10 년 = 10 명을 1 년 — Person-time 의 등가성

10 person-years 를 만드는 방법은 여러 가지:

시나리오 n 평균 추적 IR (사건 1 건 시)
1 명을 10 년 추적 1 10 10 PY 0.10 / PY
5 명을 2 년 추적 5 2 10 PY 0.10 / PY
10 명을 1 년 추적 10 1 10 PY 0.10 / PY
100 명을 0.1 년 추적 100 0.1 10 PY 0.10 / PY

constant hazard 가정 하에 시간을 어떻게 쪼개도 IR 동일. 이게 person-year 의 핵심 가치 — 동적 코호트 (사람이 들어오고 나가는) 에서도 통계적 비교 가능.

경고: constant hazard 가 깨지는 경우:

  • Survivor bias: 5 년까지 살아남은 사람은 일반인보다 건강 → 위험률이 시간에 따라 감소
  • Aging effect: 고령자가 추적될수록 위험률 증가
  • 노출 잠복기: 약물 부작용은 노출 후 1~2 년 사이에 집중

이런 경우 단일 IR 대신 시간 구간별 IR (piecewise rate) 또는 hazard function \(h(t)\) 사용.

A/B test 사례: 신기능의 6 개월 retention 분석에서 첫 7 일은 호기심 (novelty) 으로 retention 률이 높고, 30 일 이후 안정. 단일 IR 은 평균이지만, \(h(t)\) 곡선을 그려야 진짜 패턴 보임.

(Woodward, 2014, Ch.5)

2.3 Cumulative Incidence vs Survival Function

\[ \text{Cumulative Incidence}(t) = P(T \le t) = 1 - S(t) \]

여기서 \(S(t) = P(T > t)\) 는 생존함수.

  • 시점 \(t\) 까지 사건을 겪지 않은 비율
  • KM 곡선이 추정하는 양

2.4 Prevalence vs Incidence

항목 정의 시간
Incidence (발생률) 새 사건 발생 단위 시간당
Prevalence (유병률) 현재 보유자 비율 한 시점

Prevalence ≈ Incidence × 평균 사건 지속시간 (steady-state). HIV 환자 수가 늘어도 신규 발생이 줄면 prevalence 만 증가하고 incidence 는 감소.

3 시간 비교 지표 — RR 의 시간 일반화

3.1 Incidence Rate Ratio (IRR) / Difference (IRD)

\[ \text{IRR} = \frac{\text{IR}_E}{\text{IR}_{\bar E}}, \quad \text{IRD} = \text{IR}_E - \text{IR}_{\bar E} \]

  • IRR 은 RR 의 시간 일반화 — Poisson 회귀의 자연스러운 추정량
  • IRD 는 RD 의 시간 일반화 — “추가 사건/person-year”

3.2 Hazard Function — 순간 위험률

\[ h(t) = \lim_{\Delta t \to 0} \frac{P(t \le T < t + \Delta t \mid T \ge t)}{\Delta t} \]

  • \(h(t)\) 는 시점 \(t\) 까지 사건을 겪지 않은 사람이 다음 순간에 사건을 겪을 순간 비율
  • \(S(t) = \exp\left(-\int_0^t h(u)\,du\right)\) 로 생존함수와 연결
  • IR 은 \(h(t)\) 의 평균에 해당 (constant hazard 가정 시 \(h \equiv \text{IR}\))
직관: Hazard 는 “이미 살아남은 사람” 의 위험률

\(h(t)\) 의 분모가 \(T \ge t\) — 즉 시점 \(t\) 까지 사건을 겪지 않은 사람만 분모에 포함. 시간이 지나면서 이미 사건을 겪은 사람은 빠지므로 hazard 는 conditional rate 다.

비유 — 비행기 여정:

  • 1 시간 비행 중 추락할 확률: 누적 위험 (cumulative incidence)
  • 50 분 비행했는데 안 떨어졌을 때 다음 1 분에 떨어질 확률: hazard \(h(50)\)

비행이 길어질수록 이미 안전한 항로를 통과 → 남은 시간의 추락 확률은 일반적으로 일정 또는 감소 (hazard 가 시간에 따라 변동).

\(S(t)\)\(h(t)\) 의 관계 — 적분의 의미:

\[ S(t) = \exp\left(-\int_0^t h(u)\, du\right) \]

매 순간의 hazard 를 누적해서 지수의 음의 부호로 적용. 직관: 매 순간 작은 비율 \(h(u) \cdot du\) 만큼 사람이 사라지는 연속적 감소 모델 (radioactive decay 와 동일 수학).

constant hazard \(h \equiv \lambda\)\(S(t) = e^{-\lambda t}\) — exponential 분포. 이게 IR 의 base.

hazard 모양 (shape) 별 직관:

  • 상승 (increasing): aging — 고령일수록 사망 위험 증가 (Gompertz, Weibull k>1)
  • 하강 (decreasing): burn-in — 새 부품·신생아 사망률 (Weibull k<1)
  • U-자형 (bathtub): 인간 수명 — 영아·노인이 위험, 청장년 안전
  • 상수 (constant): 무작위 사건 — 방사성 붕괴, 일정한 사건 빈도 (exponential)

3.3 Hazard Ratio (HR) — 가장 중요한 시간 비교 지표

\[ \text{HR} = \frac{h_E(t)}{h_{\bar E}(t)} \]

  • 노출군의 순간 사건 위험이 비노출군 대비 몇 배인가
  • 비례 위험 (Proportional Hazards) 가정 하에 시간에 따라 일정
  • Cox PH 모델의 회귀 계수가 직접 log HR
직관: HR 1.5 의 의미 — “1.5 배 위험” 은 부정확

HR = 1.5 는 “처치군이 1.5 배 빨리 사건 발생” 도 아니고 “위험이 1.5 배” 도 아니다.

  • 정확히는: 사건이 일어나기 직전 순간에 한정하여, 처치군의 사건 발생 강도가 비노출군의 1.5 배
  • 누적 사건률 (1 - S(t)) 의 비율은 시간에 따라 다름
  • 평균 생존 시간의 비율도 아님

HR 은 직관적으로 RR 처럼 보이지만 수학적으로 다르다 (non-collapsible).

(Hernan & Robins, 2020, Ch.17 — Causal Survival Analysis)

4 표준화 지표 — 인구 비교의 lens

연령·성별 분포가 다른 인구를 비교할 때 raw rate 를 그대로 비교하면 편향. 표준화 (standardization) 가 필수.

4.1 Direct Standardization

\[ \text{표준화된 비율} = \sum_i w_i \cdot \text{IR}_i \]

  • \(w_i\): 표준 인구의 stratum 비율
  • \(\text{IR}_i\): 비교 인구의 stratum 별 IR
  • 결과: 표준 인구에 비교 인구의 stratum 별 IR 을 적용했을 때의 가상 비율

4.2 Indirect Standardization — SMR / SIR

\[ \text{SMR} = \frac{\text{관찰된 사망 수}}{\text{기대 사망 수}}, \quad \text{Expected} = \sum_i n_i \cdot \text{IR}_i^{\text{ref}} \]

  • SMR (Standardized Mortality Ratio): 사망 사건
  • SIR (Standardized Incidence Ratio): 발생 사건
  • \(\text{IR}_i^{\text{ref}}\): 기준 인구의 stratum 별 IR
  • \(n_i\): 비교 인구의 stratum 별 사이즈

해석: - SMR = 1.5 → 비교 인구의 사망이 기준 인구 대비 50% 더 많음 - 직업·지역 역학에서 핵심 (예: 광부 SMR vs 일반 인구)

직관: SMR 의 “기대값” 은 어떻게 계산되는가

광부 인구의 사망률이 일반 인구보다 높은가? 단순 비교는 위험: 광부는 평균 연령이 높아서 그냥 늙어서 더 죽을 수도 있다 (교란).

SMR 의 사고 실험:

  1. 광부 인구의 연령대별 인원: 30~44 세 1000 명, 45~59 세 800 명, 60~74 세 400 명
  2. 일반 인구 (기준) 의 연령대별 사망률: 0.5/1000, 5/1000, 50/1000 (per year)
  3. 만약 광부가 일반 인구처럼 살았다면 기대 사망 수:
    • 0.5/1000 × 1000 + 5/1000 × 800 + 50/1000 × 400 = 0.5 + 4 + 20 = 24.5 명
  4. 실제 광부 사망: 85 명 관측
  5. SMR = 85 / 24.5 ≈ 3.47 — 광부가 일반 인구보다 3.47 배 사망률

핵심 트릭: “기준 인구의 사망률을 광부 인구에 적용했을 때 기대되는 사망 수” 와 “실제 광부 사망 수” 비교. 연령 분포의 차이가 자동으로 보정됨 — 이게 “표준화” 의 의미.

Direct vs Indirect:

  • Direct = 비교 인구의 사망률을 기준 인구 분포에 적용 → 가상의 “표준화된 사망률” 도출. 비교 인구가 작거나 stratum 별 데이터 부족 시 불안정.
  • Indirect (SMR) = 기준 인구의 사망률을 비교 인구 분포에 적용 → 비교 인구가 작아도 안정적. 드물거나 작은 직업군에 특히 유용.

A/B test 비유: 신기능 retention 비교 시, 처치군과 대조군의 사용자 segment (신규/heavy/lapsed) 분포가 다르면 단순 비교 편향. SMR 처럼 “대조군의 segment 별 retention 률을 처치군 segment 분포에 적용한 기대값” 과 처치군 실제 retention 비교. CUPED 의 변형.

(Woodward, 2014, Ch.4)

4.3 Mantel-Haenszel — 층화 결합

여러 stratum 의 효과를 하나로 결합:

\[ \text{OR}_{MH} = \frac{\sum_i a_i d_i / n_i}{\sum_i b_i c_i / n_i}, \quad \text{IRR}_{MH} = \frac{\sum_i a_i (T_i^{\bar E}) / T_i}{\sum_i c_i (T_i^E) / T_i} \]

  • 교란 통제의 고전적 분석 단계 방법
  • 회귀의 base 가 되는 직관적 추정량

5 비모수·반모수 추정

5.1 Kaplan-Meier (KM) — 비모수 생존함수

\[ \hat S(t) = \prod_{t_j \le t} \left(1 - \frac{d_j}{n_j}\right) \]

  • \(d_j\): 시점 \(t_j\) 의 사건 수
  • \(n_j\): 시점 \(t_j\) 의 위험 집단 크기
  • 분포 가정 없음 — 데이터에 충실
  • 그룹별 KM 곡선 → 시각적 비교
직관: KM 의 곱셈 형태 — “매 사건마다 살아남는 비율의 누적”

KM 의 \(\prod\) 기호는 무서워 보이지만 직관은 단순:

시작: 100 명 모두 생존 (S(0) = 1.0)
↓
시점 t=1 에 5 명 사망:
  살아남는 비율 = (100-5) / 100 = 0.95
  S(1) = 1.0 × 0.95 = 0.95
↓
시점 t=2 에 censored (탈락) 10 명 (사건 아님, 분모만 줄어듦):
  살아남는 비율 그대로 = 1 (사건 없음)
  S(2) = 0.95 × 1 = 0.95
↓
시점 t=3 에 8 명 사망 (위험 집단 = 100-5-10 = 85):
  살아남는 비율 = (85-8) / 85 = 0.906
  S(3) = 0.95 × 0.906 = 0.860

각 사건 시점마다 “지금 위험에 있는 사람들 중 살아남는 비율” 을 곱한다. censored 는 분모에서 빠지지만 사건은 아님 — KM 의 핵심 장점.

왜 곱셈인가: \(S(t) = P(T > t)\) 는 “시점 \(t\) 까지 사건 없음” 이고, 이는 “각 사건 시점에서 사건 안 겪음” 의 연속이라 \(P(t_1 살아남음) \times P(t_2 살아남음 | t_1 살아남음) \times ...\) 로 분해.

시각화: KM 곡선은 사건 시점마다 한 칸씩 떨어지는 계단 함수. 일정한 곡선이 아니라 — 사건이 데이터에 있는 시점에만 떨어진다.

A/B test 비유: 사용자 1000 명 가입, 매주 일부가 churn. 8 주차에 누적 retention rate 를 보려면 KM 으로 계산 — 단순 (8 주 안 churn / 전체) 은 신규 가입자 (아직 8 주 안 됨) 를 잘못 다룬다.

5.2 Log-rank Test — 그룹 간 생존 차이 검정

\[ \chi^2 = \frac{(O_1 - E_1)^2}{V_1} \]

  • 두 KM 곡선이 동일한가의 비모수 검정
  • \(H_0\): 두 그룹의 생존함수 동일
  • 비례 위험 가정 하에 가장 강력 (Mantel-Cox 통계량)
  • Stratified log-rank: 교란 보정

5.3 Cox Proportional Hazards (PH) Model

\[ h(t \mid X) = h_0(t) \exp(\beta^T X) \]

  • \(h_0(t)\): 기준 hazard (비모수)
  • \(\beta\): 회귀 계수 — \(\exp(\beta_j)\) 가 공변량 \(X_j\) 한 단위 증가의 HR
  • 부분 가능도 (partial likelihood) 로 \(\beta\) 추정 — 기준 hazard 함수 형태 가정 없음
직관: Cox 모델의 우아함 — \(h_0(t)\) 를 모르고도 \(\beta\) 추정

선형 회귀 \(Y = \alpha + \beta X\) 는 절편 \(\alpha\) 와 기울기 \(\beta\) 를 모두 추정. Cox 는 기준 hazard \(h_0(t)\) 의 함수 형태를 전혀 가정하지 않고 \(\beta\) 만 추정한다. 어떻게?

부분 가능도 (partial likelihood) — 각 사건 시점 \(t_j\) 에서 “사건을 겪은 그 사람” 이 위험 집단 중에서 선택될 상대 확률만 사용:

\[ L_p(\beta) = \prod_{j: \text{사건}} \frac{\exp(\beta^T X_{(j)})}{\sum_{k \in R_j} \exp(\beta^T X_k)} \]

\(h_0(t)\) 는 분자·분모에 모두 들어가서 상쇄. 결과: 데이터의 시간 분포 모양을 모르고도 회귀 계수 추정 가능 — semi-parametric 의 본질.

비교: Weibull AFT 는 hazard 형태 (Weibull) 를 가정하고 추정 → 가정이 맞으면 더 효율적, 틀리면 편향. Cox 는 가정이 적어 robust.

\(\exp(\beta_j)\) = HR: 공변량 \(X_j\) 가 1 단위 증가하면 hazard 가 \(\exp(\beta_j)\) 배. 처치 = 1 vs 0 의 dummy 변수면 \(\exp(\beta_{\text{treat}})\) 가 처치-대조 HR.

왜 PH 인가: 모델이 \(h(t) = h_0(t) \cdot \exp(\beta^T X)\) 형태이므로 두 사람의 hazard 비 \(\frac{h(t \mid X_1)}{h(t \mid X_2)} = \exp(\beta^T (X_1 - X_2))\) 가 시간 \(t\) 에 무관 → “비례 위험”. 이 가정이 깨지면 다음 박스 참조.

PH 가정 — Cox 의 핵심 약점

비례 위험 가정이 깨지면 (HR 이 시간에 따라 변하면) Cox 결과는 시간 평균 HR 의 일종이 되어 해석이 모호해진다.

  • 진단: Schoenfeld residuals plot, log(-log(S(t))) plot, 시간 의존 공변량 추가 후 검정
  • 위반 시:
    • 시간 의존 공변량 (time-varying coefficient) 으로 확장
    • Stratified Cox (기준 hazard 를 stratum 별로 분리)
    • AFT (Accelerated Failure Time) 모델 사용
    • Restricted Mean Survival Time (RMST) 비교

(Hosmer, 2008; Kleinbaum, 2012)

5.4 Nelson-Aalen — 누적 hazard 추정

\[ \hat\Lambda(t) = \sum_{t_j \le t} \frac{d_j}{n_j} \]

  • KM 의 hazard 버전
  • \(\hat S(t) = \exp(-\hat\Lambda(t))\) 와 KM 이 거의 일치

5.5 AFT (Accelerated Failure Time) Model

\[ \log T = \beta^T X + \sigma \epsilon \]

  • 공변량이 사건 시간을 직접 가속·감속
  • Weibull, log-normal, log-logistic 분포 가정
  • 해석: \(\exp(\beta_j)\) = 시간의 가속 인자 (HR 이 아님)
  • PH 가정이 깨질 때 대안

6 Causal Survival Analysis

관찰 데이터에서 처치의 인과 효과를 추정하려면 교란 보정이 필요. 시간-사건 데이터에서는 추가 도전이 있다.

6.1 Time-Varying Confounding

처치가 시간에 따라 변하고 (time-varying treatment), 교란 변수도 시간에 따라 변하며, 과거 처치가 미래 교란에 영향을 줄 때 (treatment-confounder feedback) — 단순 회귀는 편향된다.

해결: g-methods (g-formula, IPW, g-estimation) — Hernan Ch.19~21.

6.2 IPW for Survival

각 개체에 안정화 IP weight \(sw_i(t)\) 를 부여한 weighted KM / Cox 로 처치 효과 추정.

\[ sw_i(t) = \prod_{k \le t} \frac{f(A_k \mid \bar A_{k-1})}{f(A_k \mid \bar A_{k-1}, \bar L_k)} \]

  • 처치-교란 피드백 보정
  • 비례 위험 가정 없이 한계 hazard ratio (marginal HR) 추정 가능

6.3 G-formula for Survival

\[ E[Y^a(t)] = \sum_l P(Y(t) = 1 \mid A = a, L = l) \cdot P(L = l) \]

  • 결과 모델로 직접 표준화
  • IPW 와 이중 강건성 (doubly robust) 결합 가능 (TMLE)

6.4 Causal HR vs 관측 HR

위에서 본 PH 가정 위반은 인과 추론 관점에서도 문제다. 처치가 random hazard 변동을 야기하면 marginal HR (인과적) 과 conditional HR (관측) 이 다르다 (non-collapsibility).

(Hernan & Robins, 2020, Ch.17)

7 메타분석 (시간 lens)

여러 연구의 HR 또는 IRR 을 결합하는 메타분석. 일반 효과 메타분석과 같지만 시간 데이터 특수성이 있다.

7.1 Pooled Effect Estimation

각 연구의 log HR 의 가중 평균:

\[ \widehat{\log \text{HR}}_{pooled} = \frac{\sum_i w_i \widehat{\log \text{HR}}_i}{\sum_i w_i} \]

  • Fixed-effect: \(w_i = 1 / \text{Var}_i\)
  • Random-effect (DerSimonian-Laird): \(w_i = 1 / (\text{Var}_i + \tau^2)\)

7.2 이질성 (Heterogeneity)

지표 정의 해석
Q statistic Cochran’s Q \(\sum w_i (\widehat{\log\text{HR}}_i - \widehat{\log\text{HR}}_{pooled})^2\) 이질성 검정 (\(\chi^2\))
Higgins \(\max(0, (Q - df) / Q) \times 100\%\) 이질성 분산 비율 (0~100%)
τ² Tau-squared DerSimonian-Laird 추정량 연구 간 분산 (random-effects)

해석 (Higgins, 2003): I² < 25% (낮음), 25~75% (중간), >75% (높음).

직관: I² = 75% 가 의미하는 것

I² 는 “관찰된 효과 변동 중 진짜 연구 간 차이로 설명되는 비율” 이다.

  • I² = 0%: 연구들이 모두 같은 효과를 추정 (변동은 표본 변동만). Fixed-effect 모델 적절.
  • I² = 50%: 변동의 절반이 연구 간 진짜 차이 (연구 모집단·프로토콜·시점이 달라서). Random-effects 사용 권장.
  • I² = 80%: 연구들이 사실상 다른 모집단을 보고 있음. Pooled effect 의 의미 의심 — sub-group 분석이나 meta-regression 필요.

비유 — 소문 합치기:

10 명의 친구에게 “오늘 점심 어디서 먹을까?” 물어보고 답을 합친다.

  • 모두 “강남역” 이라 답하면 (I² ≈ 0%) “강남역” 이 결론. 한 사람의 답으로도 충분.
  • 5 명 강남, 5 명 홍대 (I² ≈ 80%) → 단순 평균 (“강남 50%, 홍대 50%”) 은 무의미. 왜 의견이 갈리는가 (지역? 음식 선호?) 가 진짜 질문.

메타분석 보고 의무 (PRISMA 가이드라인):

  • Pooled effect + 95% CI
  • I² + τ² (이질성)
  • Forest plot (개별 연구 + pooled)
  • Funnel plot + Egger test (출판편향)
  • Sub-group analysis (이질성 클 때)

I² 만 보고하지 않고 τ² 도 보고하는 이유: I² 는 분산 비율이라 표본 크기에 의존. 작은 메타분석에서 I² = 50% 라도 절대 분산 τ² 는 작을 수 있고, 큰 메타분석에서 I² = 25% 라도 τ² 는 클 수 있음. 두 지표가 보완.

7.3 출판편향 — Funnel Plot, Egger Test

  • Funnel plot: 효과 크기 (x) vs 정밀도 (y) 산점도. 비대칭이면 출판편향 의심.
  • Egger test: funnel 의 비대칭을 회귀로 검정.

8 응용 분야

분야 핵심 지표 사례
임상 추적 KM, log-rank, Cox HR 항암제 phase III 생존 비교
직업 역학 SMR, SIR 광부 폐암 위험
A/B test retention KM, HR 신규 기능 도입 후 churn
약물 안전성 IR, IRR post-marketing surveillance
시스템 신뢰성 Weibull AFT 부품 수명 추정
정책 평가 Difference-in-Differences with time 정책 도입 전후 변화

9 예시 — 임상 추적 데이터

사례: 신약 vs 위약, 5 년 추적 (가상)
n 사건 수 Person-years IR KM 5y survival
처치군 (T) 200 30 850 0.0353 0.85
대조군 (C) 200 50 700 0.0714 0.75
  • IR_T = 30 / 850 = 35.3 / 1000 person-years
  • IR_C = 50 / 700 = 71.4 / 1000 person-years
  • IRR = 35.3 / 71.4 = 0.494 — 처치군 발생률이 50%
  • IRD = -36.1 per 1000 person-years (처치군 36 명 적게 발생)
  • HR (Cox 추정) ≈ 0.50, 95% CI [0.32, 0.78], p = 0.002
  • 5 년 RMST 차이: 약 0.30 년 (처치군이 평균 0.30 년 더 생존)

해석: HR = 0.5 는 처치군 순간 위험이 절반. RMST 는 시간 척도 (months/years) 의 절대 차이로 환자에게 직관적.

10 코드

import numpy as np
import pandas as pd
from lifelines import KaplanMeierFitter, CoxPHFitter, NelsonAalenFitter
from lifelines.statistics import logrank_test
from lifelines.utils import restricted_mean_survival_time

# 데이터 시뮬레이션 (Weibull + censoring)
np.random.seed(42)
n_per_arm = 200
T_treat = np.random.weibull(1.5, n_per_arm) * 8       # 처치군: 평균 더 김
T_ctrl  = np.random.weibull(1.5, n_per_arm) * 5
C = 5.0  # 추적 종료 시점
df = pd.DataFrame({
    "time":  np.concatenate([np.minimum(T_treat, C), np.minimum(T_ctrl, C)]),
    "event": np.concatenate([(T_treat <= C).astype(int), (T_ctrl <= C).astype(int)]),
    "treat": [1] * n_per_arm + [0] * n_per_arm
})

# 1. Incidence Rate
for arm in [0, 1]:
    sub = df[df.treat == arm]
    IR = sub.event.sum() / sub.time.sum() * 1000
    print(f"Arm {arm}: events={sub.event.sum()}, PY={sub.time.sum():.1f}, IR={IR:.1f}/1000PY")

# 2. Kaplan-Meier
kmf = KaplanMeierFitter()
fig, ax = None, None  # in real notebook: ax = plt.subplot()
for arm, name in [(1, "Treatment"), (0, "Control")]:
    sub = df[df.treat == arm]
    kmf.fit(sub.time, sub.event, label=name)
    print(f"{name} 5y survival: {kmf.survival_function_at_times(5).iloc[0]:.3f}")

# 3. Log-rank test
result = logrank_test(
    df[df.treat == 1].time, df[df.treat == 0].time,
    df[df.treat == 1].event, df[df.treat == 0].event
)
print(f"Log-rank: stat={result.test_statistic:.2f}, p={result.p_value:.4f}")

# 4. Cox PH (HR 추정)
cox = CoxPHFitter()
cox.fit(df, duration_col="time", event_col="event", formula="treat")
HR = np.exp(cox.params_["treat"])
CI = np.exp(cox.confidence_intervals_.loc["treat"])
print(f"HR = {HR:.3f}, 95% CI [{CI[0]:.3f}, {CI[1]:.3f}]")

# 5. PH 가정 검정 (Schoenfeld residuals)
cox.check_assumptions(df, p_value_threshold=0.05, show_plots=False)

# 6. RMST (Restricted Mean Survival Time)
rmst_T = restricted_mean_survival_time(KaplanMeierFitter().fit(
    df[df.treat==1].time, df[df.treat==1].event
), t=5.0)
rmst_C = restricted_mean_survival_time(KaplanMeierFitter().fit(
    df[df.treat==0].time, df[df.treat==0].event
), t=5.0)
print(f"5y RMST 차이: {rmst_T - rmst_C:.3f} years")
# SMR / SIR 계산 예시
import numpy as np
# 비교 인구 (광부): 연령대별 사이즈와 관찰 사망 수
age_groups = ["30-44", "45-59", "60-74"]
n_miners   = np.array([1000, 800, 400])
obs_deaths = np.array([5, 20, 60])

# 기준 인구 (전체 일반 인구) 의 연령대별 사망률 (per 1000)
ref_rate = np.array([0.5 / 1000, 5.0 / 1000, 50.0 / 1000])

expected = (n_miners * ref_rate).sum()
observed = obs_deaths.sum()
SMR = observed / expected
SE_logSMR = np.sqrt(1 / observed)
CI_SMR = np.exp([np.log(SMR) - 1.96 * SE_logSMR, np.log(SMR) + 1.96 * SE_logSMR])
print(f"SMR = {SMR:.2f}, 95% CI [{CI_SMR[0]:.2f}, {CI_SMR[1]:.2f}]")
# SMR > 1 + CI 가 1 미포함 → 광부 사망률이 일반 대비 유의 증가

11 관련 주제

선행 지식

후속 주제 (Epidemiology 시리즈)

Causal Inference 시리즈

A/B Test 연결

다른 카테고리 연결

Subscribe

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