생존분석 설계와 Kaplan–Meier·Cox 회귀·성향점수 매칭

임상시험과 실세계근거 분석에서 Kaplan–Meier, Cox 회귀, 성향점수 매칭으로 생존분석을 설계하고 교란을 보정하는 방법

2026-08-14 · 최초 발행 2024-04-29

시간-사건 데이터에서 설계와 추정을 연결하는 방식

임상시험과 실세계근거 분석에서 시간-사건 데이터(Time-to-Event)를 다룰 때는 연구 설계, 검열 처리, 효과 추정, 교란 보정을 분리해서 볼 수 없다. Clinical Trials Design, Kaplan–Meier, Cox Regression, Propensity Score Matching은 각각 다른 역할을 맡지만, 하나의 생존분석 체계 안에서 연결된다.

연구 질문이 분석 구조를 결정한다

임상시험 설계는 연구 질문과 비교 구조, 엔드포인트, 표본수, 무작위배정 및 눈가림 구조를 사전에 명시하는 프로토콜 설계 체계다. 설계 유형에는 평행군, 교차설계, 요인설계, 적응설계 등이 있다.

시간-사건형 엔드포인트를 사용할 때는 검열(censoring), 중도탈락, 중간분석, 이벤트 주도형 종료 규칙(Event-driven design)도 설계에 포함해야 한다. 이벤트 주도형 설계에서는 사전에 정의한 사건수에 도달한 시점에 분석한다. 연구 질문에서 엔드포인트 정의, 표본수·사건수 계획, 무작위배정·배정숨김, 중간분석·모니터링까지 이어지는 결정은 추정량의 편향과 분산에 직접 영향을 준다.

생존곡선과 위험도 비는 다른 질문에 답한다

Kaplan–Meier Estimator는 생존함수 S(t)를 비모수적으로 추정하며, 사건 발생 시점마다 계단 형태의 생존곡선을 만든다. 군 간 생존곡선 비교에는 로그랭크 검정을 사용할 수 있다. 절대시간 축에서 누적 생존확률을 보여주므로 시점별 생존확률과 중앙값을 제시할 때 직관적이다.

이 추정에는 비정보성 검열, 즉 검열과 사건이 독립이라는 가정이 필요하다. 동률이 발생했을 때는 브레슬로우 또는 에프론 처리처럼 구현상 선택이 존재한다.

Cox Proportional Hazards Regression은 위험도 비(Hazard Ratio)를 중심으로 효과를 추정하는 준모수 모델이다. 회귀계수는 부분우도(partial likelihood)로 추정한다. 비례위험가정(PH)이 충족될 때 조건부 해석이 가능하며, 공변량 조정 효과와 상호작용을 탐색할 수 있다. 시간가변 공변량, 층화(stratification), 견고분산(robust variance)으로 확장할 수도 있다.

비례위험가정 위반은 Schoenfeld 잔차나 시간상호작용으로 탐지한다. 위반이 확인되면 층화콕스, 시간가변 효과, 가속수명모형(AFT)을 대안으로 고려할 수 있다.

관찰연구에서는 배정 차이를 먼저 다룬다

성향점수 매칭(Propensity Score Matching, PSM)은 관찰연구에서 처리 배정의 조건부 확률 e(x)을 추정하고, 교란을 균형화하기 위한 기법이다. 최근접 매칭, 칼리퍼, 가중치(IPTW), 성향점수 보정 회귀처럼 매칭·가중·보정 방식을 활용할 수 있다.

이 접근은 교환가능성(비측정 교란 없음), 공변량 포지티비티(공통 지지집합), SUTVA 가정을 전제로 한다. 매칭이나 가중치 적용 뒤에는 공통 지지집합 밖 사례를 제거하고 매칭 품질을 점검해야 한다. 균형도는 표준화 평균차 SMD<0.1로 진단한다. 가중 회귀와 샌드위치 분산을 사용하면 추정량과 불확실성을 함께 추정할 수 있다.

분석 흐름에서 확인할 분기점

무작위배정관찰연구연구 질문/가설 정의엔드포인트·사건수 계획연구 유형임상시험: 배정/눈가림성향점수 모델링데이터 수집·품질관리매칭/가중치/보정검열 처리/시간-사건 데이터셋생성Kaplan–Meier생존곡선/로그랭크Cox 회귀(HR 추정)효과크기·생존확률 보고결측/이상치?사전 규칙에 따른다중대치/감도분석PH 가정 위반?층화콕스/시간가변효과/스플라인공통지지 부족?칼리퍼 강화/트리밍/대안적가중치규제 등재/임상 의사결정

무작위배정 연구에서는 배정과 눈가림을 거쳐 수집한 데이터를 검열 처리하고 시간-사건 데이터셋으로 구성한다. 관찰연구에서는 성향점수를 모델링한 뒤 매칭, 가중치, 보정을 적용해 같은 단계로 연결한다.

이후 Kaplan–Meier 생존곡선과 로그랭크 검정, Cox 회귀를 통해 생존확률과 HR을 함께 보고한다. 결측이나 이상치는 사전 규칙에 따른 다중대치와 감도분석으로 다루고, PH 가정 위반은 층화콕스·시간가변 효과·스플라인으로 대응한다. 공통 지지집합이 부족하면 칼리퍼 강화, 트리밍, 대안적 가중치를 검토한다.

분석 체계가 적용되는 장면

항암제 3상 무작위배정 임상시험

1차 평가지표로 PFS/OS를 설정하고 이벤트 주도형 설계를 적용한다. 로그랭크 검정과 Cox HR로 1차 가설을 검정한다. 하위군 분석에는 사전계획에 따른 상호작용 항을 추가하고 다중성 보정을 적용한다.

심혈관계 시술 레지스트리의 효과 추정

치료 전략 A/B를 비교할 때 로지스틱 회귀 또는 GBM으로 성향점수를 추정한 뒤 최근접 매칭을 수행한다. 균형도 SMD<0.1을 달성한 뒤 가중 Cox로 HR을 추정하고, 감도분석(E-value, 트리밍)을 병행한다.

외부 대조군 구축

단일군 시험 데이터에 맞는 환자를 RWD에서 추출한 뒤 PSM 또는 가중치로 동질화한다. KM으로 생존곡선을 비교하고, Cox로 공변량 보정 HR과 불확실성을 추정한다.

타당성, 해석, 운영에 미치는 영향

무작위배정과 적절한 검열 처리는 편향을 최소화하고 목표 검정력 ≥80% 달성에 기여한다. 층화나 공변량 조정에서는 HR 추정 효율이 5~15% 개선될 수 있으며, 이는 상황에 의존한다.

KM은 시점별 생존확률과 중앙값을 제시해 임상적 직관성을 제공하고, Cox HR은 상대위험을 표현한다. PSM 적용 뒤 SMD<0.1을 달성하면 공변량 균형화를 확인할 수 있다.

사전에 명세한 분석 파이프라인을 사용하면 데이터 잠금 뒤 자동화 분석이 가능하다. 가정 진단과 감도분석을 표준화하면 심사 대응 시간을 단축할 수 있다.

방법별 해석과 운영 특성

방법 성능(추정 효율) 확장성(대용량/고차원) 일관성(가정 충족 시) 안정성(가정 위반 민감도) 운영 편의
임상시험 설계(RCT) 매우 높음(내적 타당성) 낮음(비용·시간 부담) 높음(무작위배정) 높음(교란에 강건) 중간~낮음(운영 복잡)
Kaplan–Meier 중간(비모수) 높음 높음(비정보성 검열) 높음(모형가정 적음) 높음(시각화 용이)
Cox 회귀 높음(공변량 조정) 높음 높음(PH 가정) 중간(PH 위반 민감) 높음(광범위 지원)
PSM/가중치 상황 의존 중간~높음(매칭 비용) 중간~높음(교환가능성) 중간(중첩 부족 민감) 중간(균형 진단 필요)

lifelines로 구성한 KM·Cox·PSM 예시

전제조건: Python 3.11+, lifelines 0.27+, scikit-learn 1.4+, pandas 2.x, numpy 1.26+

# pip install lifelines scikit-learn pandas numpy
import numpy as np, pandas as pd
from lifelines import KaplanMeierFitter, CoxPHFitter
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import NearestNeighbors

# 1) 모의 데이터 생성
np.random.seed(42)
n = 1000
age = np.random.normal(60, 10, n)
sex = np.random.binomial(1, 0.5, n)
# 처리 배정(관찰연구 가정): 성향 기반 배정
logit = -2 + 0.03*age + 0.5*sex
p_treat = 1/(1+np.exp(-logit))
treat = np.random.binomial(1, p_treat)
# 진짜 위험도: HR_treat = 0.75
base_haz = 0.03
linpred = np.log(0.75)*treat + 0.01*(age-60) + 0.2*sex
T = np.random.exponential(1/(base_haz*np.exp(linpred)), n)
C = np.random.exponential(30, n)  # 독립 검열
time = np.minimum(T, C)
event = (T <= C).astype(int)

df = pd.DataFrame({"time": time, "event": event, "treat": treat, "age": age, "sex": sex})

# 2) Kaplan–Meier
km = KaplanMeierFitter()
for g, dfg in df.groupby("treat"):
    km.fit(durations=dfg["time"], event_observed=dfg["event"], label=f"treat={g}")
    # 생존확률 예시 출력
    print(km.survival_function_.head())

# 3) Cox 회귀(보정 전)
cph = CoxPHFitter()
cph.fit(df, duration_col="time", event_col="event", formula="treat + age + sex")
print(cph.summary.loc[["treat"]][["exp(coef)", "p"]])

# 4) Propensity Score Matching(최근접 1:1, 칼리퍼 0.2*SD(logit))
X = df[["age", "sex"]]
ps_model = LogisticRegression(solver="lbfgs").fit(X, df["treat"])
ps = ps_model.predict_proba(X)[:,1]
logit_ps = np.log(ps/(1-ps))
caliper = 0.2*logit_ps.std()

treated = df[df.treat==1].copy()
control = df[df.treat==0].copy()
nbrs = NearestNeighbors(n_neighbors=1).fit(logit_ps[df.treat==0].reshape(-1,1))
dist, idx = nbrs.kneighbors(logit_ps[df.treat==1].reshape(-1,1))
pairs = [(treated.index[i], control.index[j]) for i,j in enumerate(idx.flatten()) if abs(dist[i][0]) <= caliper]
matched_idx = [i for i,_ in pairs] + [j for _,j in pairs]
dm = df.loc[matched_idx].copy()

# 매칭 데이터로 Cox
cph_m = CoxPHFitter()
cph_m.fit(dm, duration_col="time", event_col="event", formula="treat + age + sex")
print(cph_m.summary.loc[["treat"]][["exp(coef)", "p"]])

PH 가정은 Schoenfeld 잔차와 시간상호작용을 포함해 점검한다. 매칭 뒤에는 표준화 평균차 SMD 계산과 <0.1 기준을 활용해 균형을 진단한다. 결측값이 발생하면 사전에 정의한 다중대치 절차와 감도분석을 병행한다.

분석의 일관성은 설계와 데이터에서 시작해 검열·보정·가정 점검을 거쳐 효과 추정과 불확실성 보고로 이어진다. 가정 진단과 감도분석의 표준화, 자동화 파이프라인, 재현가능 리포팅 체계는 이 흐름을 운영 가능한 분석 체계로 만든다.

의료 통계생존분석임상시험성향점수 매칭Cox 회귀