ExpertIndependently reviewed, not yet spot-checked by a human

Time-dependent covariates

When exposure changes during follow-up, Cox needs a (start, stop] long table rather than one row per person. How tmerge() builds it, why an Andersen-Gill model for recurrent events must use a robust variance, whether a repeated lab value should enter as its baseline or its current reading, when a landmark analysis is the better choice, and why a time-dependent hazard ratio cannot be used for prediction.

Two things that get conflated

They share a name and they are entirely different problems:

Time-dependent covariateTime-varying coefficient
What movesxx moves: this person’s exposure status today differs from three months from nowβ\beta moves: exposure is fixed, but its effect grows or decays over time
The modelh(tx)=h0(t)exp(βx(t))h(t \mid x) = h_0(t) \exp(\beta \, x(t))h(tx)=h0(t)exp(β(t)x)h(t \mid x) = h_0(t) \exp(\beta(t) \, x)
Typical examplesReceiving a transplant, starting dialysis, today’s serum bilirubin, current medicationEarly surgical hazard, delayed immunotherapy effect, waning vaccine protection
What it solves“The value at baseline does not represent the whole of follow-up”Proportional hazards has been violated”
Where it livesThis pageB3-04

The (start, stop] long table: one person, many rows

Ordinary survival data gives each person one row: a time, an event indicator, and some fixed covariates. Once exposure moves, that shape is not enough, because “what is this person’s xx” has different answers at different moments.

The fix is to cut each person into segments inside which xx is constant. One row per segment, with columns for the half-open interval (tstart, tstop], whether an event occurred at the end of that segment, and the covariate values that applied during it.

Two timeline panels side by side. On the left, six patients from the Stanford heart transplant study, one horizontal line each; a patient who receives a transplant changes colour at that moment, splitting the line into two segments, and a red dot at the end of a line marks death. On the right, six patients with primary biliary cholangitis, each line cut into many short segments separated by thin white gaps, with the shade of each segment showing which tertile of the distribution that period's serum bilirubin fell into.
Left: an exposure that switches at most once, so a person has at most two rows. Right: a lab value measured at scheduled visits, so a new segment starts at every visit — one person can easily have a dozen rows. Both feed the model exactly the same data structure.Plotting script figures/scripts/B3-06-time-varying.R

What matters is that this structure does not turn one person into several people. Cox estimation happens entirely within the risk set at each event time (see B3-01): at time tt the model only asks “of the people still under follow-up right now, what is each one’s xx at this instant”. Every row of the long table is just a lookup entry answering that question, and a person has exactly one row covering time tt, so they are counted once.

tmerge(): turning a wide table into a long one

Cutting intervals by hand goes wrong easily — overlaps, missing segments, an event recorded on the wrong row — and tmerge() in the survival package exists to do exactly this. Its mental model: first build a skeleton holding only the follow-up interval and the outcome, then layer events and time-dependent variables onto it one at a time.

Three main verbs:

FunctionMeaningUsed for
event(time, status)Record an event at time and cut follow-up thereThe primary outcome
tdc(time, value)From time onward the covariate becomes value (time-dependent covariate)Lab values, medications, surgery
cumevent(time)A running count, incremented from time onward“How many have happened so far”

Run it on the Stanford heart transplant data (103 patients on the waiting list, 69 of whom received a transplant) and you get 170 rows: one each for the 34 who were never transplanted, two each for the 67 who were, and then 2 patients transplanted on day 0 — tdc() cannot cut an interval at time zero, so they get a single row too, and that row already carries transplant equal to 1.

34 + 2 = 36 patients with one row, plus 67 with two rows, is exactly the 103 patients in the study; and 67 + 2 = 69 received a transplant. Do both sums every time you build a long table. The common misuses table below says that a badly built long table throws no error and simply returns the wrong answer quietly — those two day-0 patients are that sentence made concrete.

Repeated measurements: baseline value or current value

pbcseq is the follow-up data from a primary biliary cholangitis cohort: 312 patients with scheduled blood tests, a median of 5 visits and a maximum of 16, followed for up to 12.5 years, during which 125 died. Reshaped into a long table it becomes 1807 rows.

Bilirubin is the single most important prognostic marker in this disease, and it rises as the disease advances. Using the baseline measurement and using “the most recent value as of right now” give appreciably different answers:

CovariateBaseline value: HR95% CICurrent value: HR95% CI
log(bilirubin)2.9202.387–3.5724.0043.169–5.058
log(albumin)0.0320.008–0.1220.0080.003–0.021
Age at entry1.0401.023–1.0571.0471.028–1.067
Concordance (C statistic)0.8330.910
Two panels side by side. On the left, serum bilirubin trajectories on a log scale for 24 randomly selected patients with primary biliary cholangitis: red lines are patients who died during follow-up and mostly trend upward, climbing steeply near the end, while pale blue lines are patients still alive and stay roughly flat. On the right, two horizontal confidence intervals: the upper one is the hazard ratio of 2.920 using baseline bilirubin only, the lower one is 4.004 using the current value, and the intervals overlap slightly between 3.169 and 3.572 while the point estimate for the current value falls outside the baseline interval.
Left: bilirubin does not stay where it started, and the trajectory shapes differ between those who died and those who did not. Right: same patients, same outcome, one change in how the covariate is defined, and the hazard ratio for log bilirubin moves from 2.920 to 4.004.Plotting script figures/scripts/B3-06-time-varying.R

The hazard ratio from baseline bilirubin is the smaller one, and there is no mystery about why: the baseline value is a proxy for the current value that gradually stops working. The longer follow-up runs, the further that one early blood draw sits from the patient’s condition right now, and the association is diluted — regression dilution. Using the current value removes that layer of dilution.

Recurrent events: Andersen-Gill and the robust variance

Some outcomes happen again and again: infections, asthma attacks, heart failure readmissions, seizures. One row per person keeps only the first and discards the rest.

cgd is a randomised trial in chronic granulomatous disease comparing interferon gamma with placebo for the prevention of serious infection. 128 children, 76 infections in total during follow-up, 17 of the children having more than one and the worst-affected child having 7.

Keeping only the first event throws away 32 events, which is 42.1% of the total.

The Andersen-Gill (AG) model takes an unglamorous approach: cut each person’s follow-up into intervals running from one event to the next, throw them all into a single Cox model, and treat them as separate observations. The data structure is exactly the long table from the previous section.

AnalysisEvents usedHR (interferon vs placebo)95% CISE of the coefficient
First event only440.3350.174–0.6450.335
Andersen-Gill, no robust variance760.334 (same as the row below)0.201–0.558 (too narrow)0.261 (understated)
Andersen-Gill with a robust (cluster) variance760.3340.181–0.6160.312

Landmark analysis: the blunter option that is easier to explain

A time-dependent model is not the only way out. Landmark analysis picks a timepoint LL, keeps only the people who survived to LL, groups them by their status at LL, and restarts the clock there.

Why that avoids immortal time bias: everything needed to assign groups is already known at LL, and time before LL is excluded from both groups alike.

Using the Stanford heart transplant data with a landmark at day 30:

Two panels side by side. On the left, two Kaplan-Meier curves after the day 30 landmark: a blue curve for patients not yet transplanted and a green curve for those already transplanted, crossing back and forth throughout follow-up without clearly separating. On the right, hazard ratios with confidence intervals from three landmark timepoints (days 14, 30 and 60); the point estimate moves from above 1 to below 1 and all three intervals cross 1.
Left: the 79 patients who survived to day 30, split by whether they had been transplanted by then. Right: change the landmark and the point estimate moves with it — not merely statistical noise, since the three analyses define three different populations and three different groupings.Plotting script figures/scripts/B3-06-time-varying.R
LandmarkKeptDroppedTransplanted by thenHR95% CIp
Day 148815211.4410.812–2.5580.212
Day 307924350.9150.527–1.5890.752
Day 606439450.8080.407–1.6040.542

None of the three landmarks reaches statistical significance — every confidence interval crosses 1 — which agrees with the time-dependent model in B3-01. What agrees is the absence of a detected difference, not the direction of the point estimate: B3-01’s hazard ratio is above 1, whereas two of these three are below it. And the point estimate travels from 1.441 at day 14 to 0.808 at day 60, while the number of patients retained falls from 88 to 64.

Time-dependent covariateLandmark analysis
Data usedAll of itOnly those alive at LL, and only follow-up after LL
Group definitionUpdated at every instantFrozen at LL (anyone who switches later is misclassified)
Statistical efficiencyHigherLower, and the later LL is, the more is discarded
Interpretability for readersPoorer — the hazard ratio matches no baseline groupingBetter — it is just two groups’ KM curves
Main riskData-wrangling errors (overlapping intervals, covariates peeking at the future)The choice of LL; picking LL after the fact is data dredging

An interpretive limit: a time-dependent hazard ratio cannot be used for prediction

This is the most important section on the page, and the one most often skipped.

The hazard ratio for a time-dependent covariate is a contemporaneous association: it says that at time tt, people whose x(t)x(t) is high have a higher hazard at that instant. It is not a predictive statement.

The reason: to use this model to compute someone’s probability of surviving the next five years, you would need to know their x(t)x(t) at every instant of those five years — which is exactly what you do not have. How bilirubin will move is itself unknown; if you knew it, you would probably already know the outcome.

Run it yourself

library(survival)

# -- 1. What a long table looks like --
data(cgd, package = "survival")
head(cgd[cgd$id %in% c(1, 2), c("id", "tstart", "tstop", "status", "treat", "enum")])

# -- 2. tmerge(): building a long table from a wide one --
# Skeleton: one row per person, the follow-up interval and the outcome
base <- subset(pbc, id <= 312, select = c(id:sex, stage))
d <- tmerge(base, base, id = id, death = event(time, status == 2))
# Layer on the time-dependent labs; tdc() takes effect AFTER the stated moment
d <- tmerge(d, pbcseq, id = id,
            bili = tdc(day, bili), albumin = tdc(day, albumin))
head(d[d$id == 2, c("id", "tstart", "tstop", "death", "bili", "albumin")])

# -- 3. Baseline value vs current value --
b <- merge(base, pbcseq[!duplicated(pbcseq$id), c("id", "bili", "albumin")], by = "id")
coxph(Surv(time, status == 2) ~ log(bili) + log(albumin) + age, data = b)
coxph(Surv(tstart, tstop, death) ~ log(bili) + log(albumin) + age, data = d)

# -- 4. Recurrent events: Andersen-Gill --
coxph(Surv(tstart, tstop, status) ~ treat, data = cgd)                  # SE is wrong
coxph(Surv(tstart, tstop, status) ~ treat + cluster(id), data = cgd)    # robust variance
# PWP: stratify by event number, so the k-th event has its own baseline hazard
coxph(Surv(tstart, tstop, status) ~ treat + strata(enum) + cluster(id), data = cgd)

# -- 5. Landmark analysis --
data(heart, package = "survival")
L <- 30
lm <- subset(jasa, futime >= L)
lm$g <- factor(ifelse(!is.na(lm$wait.time) & lm$wait.time <= L, "tx", "no"))
coxph(Surv(futime - L, fustat) ~ g, data = lm)
plot(survfit(Surv(futime - L, fustat) ~ g, data = lm))

# -- 6. Check the reshaping for errors (never skip this) --
# Intervals must not overlap, must not have tstop <= tstart, and must join up
with(cgd, tapply(seq_along(id), id, function(i)
  all(tstart[i][-1] == tstop[i][-length(i)]))) |> table()

Verified with R 4.6.0 and survival 3.8.6

How to read this in a paper

  1. When was the exposure determined. Whenever the grouping variable can only be known after baseline — received surgery, responded, completed the course, started a drug — go to the Methods and find out whether they used a time-dependent variable, a landmark, or nothing at all.
  2. When the time-dependent covariate was measured, and how it entered the model. “The most recent value”, “the mean over the interval” and “the value lagged by a week” are three different definitions and give different results. None stated means not reproducible.
  3. Whether recurrent events used a robust variance. Look for “robust”, “sandwich”, “cluster”, “covs(aggregate)”. Absent, widen the confidence intervals by roughly a fifth in your head.
  4. Which recurrent event model. AG, PWP, WLW and frailty models rest on different assumptions; “a Cox model for recurrent events” is not enough.
  5. How LL was chosen for a landmark analysis, and how many people it discarded. Was it in the protocol; and are the characteristics of those excluded — the people who died before LL — described.
  6. Whether a time-dependent model was used for prediction. A sentence like “this model’s C statistic was X, better than the baseline model” attached to a model containing time-dependent covariates is an unfair comparison.

Common misuses

MisuseWhy it is wrong
Grouping at baseline by a status only known laterImmortal time bias; see B3-01
Confusing a time-dependent covariate with a time-varying coefficientThe first is a moving exposure, the second a violated proportional hazards assumption; the fixes are entirely different
Building the long table and never checking the intervalsOverlaps, negative lengths and events on the wrong row raise no error — they just quietly return the wrong answer
Letting a covariate take effect at the instant of the eventThat writes outcome information into the exposure; a dying state gets read as a strong predictor
Andersen-Gill for recurrent events without a robust varianceCorrelated repeated observations are counted as independent information, and standard errors are clearly understated
Keeping only the first event without saying soThe discarded events are usually the majority, and mostly come from the sickest patients
Choosing between AG, PWP and WLW without justificationTheir assumptions and risk set definitions differ, and results can differ substantially
Choosing the landmark after seeing the dataThe point estimate moves with L, so a post hoc choice is selective reporting
A landmark analysis that never says how many people were excludedReaders cannot judge whether the remaining population still addresses the original question
Using a time-dependent model for survival curves or n-year survivalThose require future covariate trajectories, which is exactly what is unknown
Claiming better prediction from a time-dependent model’s C statisticIt uses information generated after the moment of prediction, so the comparison is unfair
Adjusting for an exposure-affected time-dependent variable as an ordinary covariateIt is both mediator and confounder; standard Cox cannot handle it, a marginal structural model can

Reproducing every number on this page

/opt/homebrew/bin/Rscript figures/scripts/B3-06-time-varying.R

Read the figure

The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.

The two variance estimators for an Andersen-Gill model give the same hazard ratio but different standard errors. Which should be reported, and why?

Show the answer and why

Correct answer: 0.312 - it does not assume that one patient's repeated infections are independent

0.312 is the robust standard error. The naive 0.261 assumes a patient's repeated infections are independent, and they are not - some children simply relapse often, so their second event carries less new information than independence implies. Ignoring that makes intervals too narrow and p-values too small while the point estimate is unchanged, so nothing in the hazard ratio column looks wrong. 0.335 comes from the first-event-only model, which does avoid the correlation, at the cost of discarding more than half the events - a different question, not a fix for this one.

If the same CGD data are analysed using only each patient's first infection, what is given up?

Show the answer and why

Correct answer: 32 events are discarded, all of them somebody's second or later infection

76 events in total, 44 once only first events count, and the difference of 32 is entirely second-and-later infections - close to half the events, and not a random half: they fall precisely on the children who relapse most. So first-event-only analysis does not merely shrink the sample, it removes the tendency to relapse from the analysis altogether. Papers taking this route rarely say in the methods what was dropped; the reader sees only a smaller event count.

Landmark analysis excludes anyone whose event occurred before the landmark day. What happens when the landmark moves from day 14 to day 30?

Show the answer and why

Correct answer: 24 are excluded, and they are exactly the patients whose events came earliest

A landmark at day 30 excludes 24 patients; the earlier landmark excludes only 15 - later landmark, more exclusions. What matters is not the count but who: those excluded are the ones whose events came first, so the post-landmark population is healthier than the one enrolled. That is not a bias but the design working as intended, and what it buys is the removal of immortal time bias. The price is that conclusions apply to patients who survived to the landmark day and cannot be carried back to the original cohort. 79 is how many the day-30 version kept.

Watch next

存活分析(Survival Analysis)第二部分
繁中Ming-Chieh Shih· 18 minIn Mandarin, continuing from part one into the Cox model and data structure. It has no section on time-dependent covariates as such, but it makes clear what shape of data the model consumes — a warm-up for the second section here.
【Hands-on】L12 R:Survival Analysis
繁中MeDA(臺大公衛洪弘教授)· 19 minA hands-on R session in Mandarin showing how survival data is prepared and modelled. Watch it first if you want the code on this page to actually run.
The Statistics of Life and Death | Survival Analysis
ENVery Normal· 15 minIn English, rebuilding survival analysis from the definition of the hazard function. The claim on this page that "the risk set is reassembled at every event time" lands much better after watching it.

Sources and licences

This page is original writing

Report a content problem

The statistics on this site are written by AI and reviewed by AI; a human only spot-checks. What you can see may be what we cannot.

The more specific, the more fixable — e.g. which sentence disagrees with which textbook or paper.

Needed only if you want a reply; reports without it are still read.

Sent along with your report

These are attached automatically. You can drop any of them.