시간 의존 공변량·경쟁 위험·Frailty 모델 실무 설계
시간 의존 공변량, 경쟁 위험, frailty 모델의 데이터 구조와 모형 선택, 진단·검증 기준을 정리한다.
2026-08-14 · 최초 발행 2024-04-29
동적 위험과 경쟁 사건을 같은 분석 틀에 담기
임상·제조·금융 분야에서는 사건이 언제 발생했는지뿐 아니라 위험 요인이 시간에 따라 어떻게 바뀌었는지도 함께 다뤄야 한다. 어떤 사건은 다른 사건이 일어나면 더는 관찰할 수 없고, 같은 설비군이나 기관에 속한 개체는 관측되지 않은 공통 위험을 공유하기도 한다.
이때 시간 의존 공변량(Time-dependent covariates), 경쟁 위험(Competing risks), frailty 모델은 서로 다른 문제를 맡는다. 분석 전에 각 문제를 구분해 두어야 해석 목적과 데이터 구조, 모형 선택이 어긋나지 않는다.
시간 의존 공변량은 시간이 흐르며 값이 달라지는 설명변수를 위험함수에 포함한다. 위험함수 (h(t|X(t)))에서 (X)가 시간 (t)의 함수로 정의되는 형태다. 누적 약물 용량처럼 분석 대상 내부에서 변화하는 변수와 시장 지표처럼 외부 환경에 따라 변하는 변수를 구분할 수 있으며, 자료는 시작·종료·사건 구간을 갖는 카운팅 프로세스 형식으로 변환해야 한다.
경쟁 위험은 여러 사건 유형 가운데 최초로 발생한 사건이 상호 배타적인 상황을 다룬다. 한 사건이 발생하면 다른 사건의 관찰 가능성이 사라진다. 원인특이 위험함수(cause-specific hazard)는 원인별 위험률을, 부분분포 위험함수(subdistribution hazard; Fine-Gray)는 누적발생률(CIF)을 통한 원인별 절대위험을 해석하는 데 사용한다.
Frailty 모델은 관측할 수 없는 이질성을 위험함수의 곱셈 무작위 효과로 반영한다. 개체 또는 집단 단위의 취약성 분산을 통해 클러스터 상관 구조를 다루며, 공유(shared) frailty는 집단 내 상관을, 개별 frailty는 개인 간 이질성을 모델링한다. 실무에서는 감마와 로그정규 분포를 사용한다.
자료 구조가 모형의 해석 범위를 결정한다
시간 의존 공변량을 넣을 때는 각 행이 ([시작, 종료)) 구간과 해당 시점의 공변량 스냅샷을 보유하도록 긴 형식(long format)으로 자료를 나눈다. Surv(start, stop, event)는 구간별 위험집합을 갱신하는 데 쓰인다.
시간 의존 공변량과 시간가변 효과는 같은 문제가 아니다. 전자는 공변량 값 자체가 시간에 따라 변하는 경우이고, 후자는 계수가 시간에 따라 달라지는 경우다. 시간가변 효과가 필요하면 tt() 또는 상호작용으로 검정한다.
경쟁 위험에서는 먼저 분석 질문을 정한다. 원인특이 Cox는 관심 원인 (k)의 사건을 event로 두고 나머지 원인을 검열로 처리한다. 공변량이 위험률에 미치는 영향과 병인학적 연관성을 해석할 때 적합하다. Fine-Gray는 부분분포 위험 모형으로 CIF를 직접 모델링하므로 예측과 절대위험 커뮤니케이션에 유리하지만, 병인 해석에는 신중해야 한다.
공유 frailty는 집단 내 상관과 과산포를 다룬다. 분산 (\theta)가 0이면 이질성이 없는 모형으로 환원된다. 감마 분포는 계산 안정성과 해석 측면에서, 로그정규 분포는 두꺼운 꼬리를 허용한다는 점에서 선택할 수 있다. 어느 분포를 쓰든 수렴성과 민감도 점검이 필요하다.
분석 흐름과 실패 지점
추정 단계에서는 Cox의 부분우도, Fine-Gray의 준우도, frailty의 EM 또는 적분근사를 사용한다. 타이 처리와 위험집합 구성의 정확성이 결과에 직접 영향을 준다.
검증에서는 Schoenfeld 잔차로 비례위험 가정을 확인하고, Gray’s test로 CIF를 비교한다. 군집 상관은 변동계수 또는 (\theta) 추정으로 평가하며, 강건 분산(sandwich) 사용을 고려한다.
도메인별 적용 방식
장기 이식 대기자 분석에서는 이식과 사망이 경쟁 위험이 된다. Fine-Gray로 원인별 누적발생률을 추정하면 대기기간의 절대위험을 전달할 수 있다. 크레아티닌 같은 실험실 지표는 갱신되는 시간 의존 공변량으로 반영해 경보 임계치 설정에 사용할 수 있다.
구독 비즈니스에서는 유료전환과 이탈을 경쟁 사건으로 둘 수 있다. 마케팅 개입의 상대효과는 원인특이 HR로, 절대효과는 CIF로 분리해 보고한다. 최근 접속, 이벤트 카운트, 가격 변동은 구간별 공변량으로 투입한다.
제조 설비 신뢰성 분석에서는 라인이나 설비군 단위의 공유 frailty로 공통 리스크를 반영한다. 부하와 온도 센서 데이터 스트림은 구간화해 시간 의존 공변량으로 사용하고, 위험 급등 감지와 예지보전 우선순위에 연결한다.
약물역학 RWE에서는 처방 시작·중단·교체를 시간 의존 노출로 정의해 immortal time bias를 제거한다. 사망이 중단 또는 이벤트 관찰을 방해한다면 경쟁 위험으로 보고 CIF 해석을 택한다.
적합 전 확인할 데이터와 검증 항목
시간 의존 공변량 자료는 개체·구간 단위의 행으로 구성하고, ([t_start, t_stop)), event ∈ {0,1}을 지켜야 한다. 구간의 불연속과 중복은 허용하지 않는다.
경쟁 위험 자료는 status ∈ {0=검열, 1=원인 A, 2=원인 B, …}로 상태를 정의한다. CIF가 목적이면 Fine-Gray를, 병인 해석이 목적이면 원인특이 Cox를 고른다.
Frailty 분석에는 cluster_id 필드가 필요하다. 군집 크기 분포를 확인하고, 극단적으로 작은 군집에 편중되면 추정이 불안정해질 수 있음을 점검한다.
모형을 적합한 뒤에는 타이 처리 방법(Efron/Breslow/Exact)을 명시한다. 비례위험 가정이 위반되면 시간가변 효과를 도입하거나 strata를 적용한다. 강건 분산의 검증은 부트스트랩과 병행하고, CIF 곡선이 교차한다면 원인별 경쟁 구조를 다시 확인한다. Frailty 분산 (\theta)의 신뢰구간과 분포·초기값에 대한 민감도도 함께 보고한다.
선택 기준을 해석 목적과 연결하기
| 모델 | 일관성(해석) | 확장성(공변량/상호작용) | 안정성(수렴/강건성) | 운영 편의(구현/툴) | 성능(예측/시간) |
|---|---|---|---|---|---|
| Cox + 시간 의존 | 상대위험 해석 명확, 외삽 주의 | 매우 높음, 다양한 시간가변 효과 가능 | 높음, 단 구간화 품질 의존 | 우수(R, Python 광범위 지원) | 예측 좋음, 적합 빠름 |
| 원인특이 Cox | 병인·상대위험 해석 우수 | 높음, 원인별 모형 분리 | 높음, 단 사건 희소 시 불안정 | 우수(survival, lifelines) | 빠름 |
| Fine-Gray | CIF 직접해석(절대위험) 강점 | 보통, 일부 상호작용 제한적 | 중간, 사건 경쟁구조 민감 | 양호(cmprsk 등 전용 필요) | 보통 |
| Cox + 공유 frailty | 집단 상관 반영, 과산포 완화 | 높음, 다층 확장 가능 | 중간~높음(분포/초기값 민감) | 양호(R 적합, Py 제한) | 보통 |
R로 확인하는 시간 의존·경쟁 위험·frailty 적합
전제조건: R ≥ 4.2, survival ≥ 3.5, cmprsk ≥ 2.2
# 패키지
library(survival)
library(cmprsk)
set.seed(42)
# 1) 모의 데이터 생성
n <- 600
grp <- sample(1:60, n, replace=TRUE) # 클러스터(공유 frailty 가정)
x0 <- rbinom(n, 1, 0.5) # 고정 공변량
base_haz <- 0.02
# 시간 의존 공변량: 3개 구간으로 분할
make_td <- function(i){
k <- sample(2:4, 1)
tcuts <- sort(runif(k-1, 0.1, 3.0))
times <- c(0, tcuts, 5)
# 구간별 시간의존 공변량: 이동평균 형태
zt <- runif(k, -0.5, 0.5)
# 사건 시간 시뮬레이션(단순화)
lam <- base_haz * exp(0.6*x0[i] + 0.3*zt + rnorm(1, 0, 0.3)) # frailty 근사
dt <- rexp(k, rate = pmax(lam, 1e-4))
stopt <- pmin(cumsum(dt), diff(times))
event_idx <- which(cumsum(dt) <= diff(times))
event <- if(length(event_idx)) as.integer(tail(event_idx,1)==seq_len(k)) else 0
data.frame(id=i, grp=grp[i], x0=x0[i],
tstart=head(times, -1),
tstop=tail(times, -1),
zt=zt,
event=0L)
}
td_list <- do.call(rbind, lapply(1:n, make_td))
# 경쟁 위험 코드 추가: 원인1/원인2 중 하나 발생 확률 부여
td_list$cr_status <- 0L
ix <- sample(1:nrow(td_list), size = floor(0.15*nrow(td_list)))
td_list$cr_status[ix] <- sample(c(1L,2L), length(ix), replace=TRUE, prob=c(0.6,0.4))
# 2) 시간 의존 공변량 Cox (카운팅 프로세스)
fit_td <- coxph(Surv(tstart, tstop, event) ~ x0 + zt + cluster(id),
data = td_list, ties = "efron")
summary(fit_td)
# 3) 원인특이 Cox (원인1에 대해)
# 개체 단위 time/status 생성 예시(최초 발생 기준)
agg <- aggregate(cbind(tstop, cr_status) ~ id + x0 + grp, td_list, function(v) tail(v,1))
fit_cs <- coxph(Surv(tstop, cr_status==1) ~ x0 + strata(grp),
data = agg, ties = "efron")
summary(fit_cs)
# 4) Fine-Gray (부분분포 위험, 원인1의 CIF)
fg <- crr(ftime = agg$tstop, fstatus = agg$cr_status,
cov1 = as.matrix(agg["x0"]))
fg
# 5) 공유 frailty Cox (감마)
fit_frailty <- coxph(Surv(tstop, cr_status!=0) ~ x0 + frailty(grp, distribution="gamma"),
data = agg, ties = "efron")
summary(fit_frailty)
# 6) 진단
cox.zph(fit_td) # 비례위험 가정 진단
# CIF 곡선
plot(cuminc(agg$tstop, agg$cr_status, cencode = 0), lty=1:2, col=1:2)
시간 의존 공변량에는 Surv(start, stop, event)가 필요하며, 구간 불연속이나 중복이 있으면 에러가 발생한다. 경쟁 위험에서는 cause-specific과 Fine-Gray의 해석 목적이 다르므로, 동일 공변량에서도 계수가 일치하지 않을 수 있다. Frailty 모형은 분산 (\theta)의 유의성과 수렴 메시지를 확인하고, 군집 수준의 과소·과대분산이 있으면 민감도 분석을 수행한다.
편향과 운영 해석에서 얻는 변화
시간 의존 노출을 반영하면 immortal time bias와 시간 불일치에서 비롯되는 HR 추정 편향을 줄일 수 있다. 내부 검증 기준 c-index 0.02~0.05p 개선 사례가 있다.
CIF는 절대위험을 전달할 수 있게 하며, 원인별 기여도를 나누어 정책과 임상 의사결정에 연결할 수 있다. 공유 frailty로 클러스터 이질성을 흡수하면 경보 오탐률을 낮추는 데 도움이 되며, 알람 PPV 5~15%p 개선 사례가 있다. 재현성 높은 파이프라인을 구성하기도 수월해진다.