Celeus

How to interpret a hazard ratio in Cox regression

What a hazard ratio of 2 does and does not mean, how the reference group and the unit change it, and how to report it with a confidence interval.

Updated . Written by Matt Gencer.

On this page

A hazard ratio compares how fast events happen in two groups, not how many people have the event. A ratio of 2 means that, at any moment, among units still event-free, the rate in one group is about twice the rate in the other. That is a statement about rates, and the most common ways of putting it into words turn it into something else.

This post is about reading and reporting the number. Fitting the model, and checking that one number is a fair summary of the follow-up, are covered in Kaplan-Meier and Cox regression for survival data and in the full workflow in Survival analysis: Kaplan-Meier, Cox and AFT in R. Here we take a fitted Cox proportional-hazards model and ask what each hazard ratio claims, on which scale, and how to say it without overstating it. For the full coxph() workflow in R, see Cox regression in R.

The worked example

The data are the public NCCTG advanced lung cancer cohort shipped with R’s survival package: 228 people followed from enrolment, time in days to death or last contact. This is an observational research dataset used to show how the numbers read. Nothing here is a statement about the outlook for any individual.

One person has no performance score and is dropped, which leaves 227 people and 164 deaths. The model has three predictors: sex (coded 1 for men and 2 for women), the physician-rated ECOG performance score (0 to 3, entered as a number) and age in years.

Term Hazard ratio 95% CI p
Sex (female vs male) 0.575 0.414 to 0.799 < 0.001
ECOG score (per point) 1.590 1.273 to 1.986 < 0.001
Age (per year) 1.011 0.993 to 1.030 0.232

Every sentence below reads one of these rows, and the same choices of reference group, unit and wording apply to any Cox output.

What a hazard ratio of 2 does and does not mean

The hazard is the instantaneous event rate at time t, among those still event-free at t. The Cox model says one unit’s hazard is the baseline hazard multiplied by a factor that depends on its covariates (Cox 1972). The ratio of two units’ hazards is the ratio of those factors, and the baseline cancels. A hazard ratio of 2 therefore means the comparison group’s rate is twice the reference group’s rate, whenever you look. Three readings that sound close are wrong.

  • “Twice the risk.” Risk is a cumulative probability, the proportion who have had the event by a given time. A hazard is a rate. Both rise or fall together, but they are not the same size. With a rare event over short follow-up the hazard ratio and the risk ratio are close; as the event becomes common they separate (Spruance and colleagues 2004). The same distinction is spelled out for odds in odds ratio vs relative risk.
  • “Twice as many will have the event.” A rate ratio of 2 does not say how many. A group can have double the rate and still have few events, if follow-up is short or the baseline rate is low.
  • “The event comes twice as fast.” A doubled hazard does not in general halve the time. That holds only when the hazard is constant over follow-up; otherwise times depend on the shape of the whole hazard curve. A model that works directly on time, such as an accelerated failure time model, reports a time ratio, which is a different quantity.

For a ratio below 1, subtract it from 1. The sex row says women had an estimated hazard 0.575 times that of men, which is a 42.5% lower hazard, not “42.5% less likely to die” and not “42.5% longer survival”.

The same ratio, different absolute gaps

Under proportional hazards the survival curve of one group is the other’s curve raised to the power of the hazard ratio. That is a one-line way to see why a constant ratio gives a changing absolute difference. Take the unadjusted ratio for women versus men from the Kaplan-Meier companion run, 0.588 (95% CI 0.424 to 0.816), and two moments of follow-up at which the survival proportion in the male group is 0.9 and 0.5. The implied proportion in the female group is 0.9 raised to 0.588, about 0.940, and 0.5 raised to 0.588, about 0.665. The same ratio is a gap of about 4 percentage points at the first moment and about 17 at the second.

These two baseline values are chosen for the illustration, and the arithmetic needs the proportional hazards assumption to hold. The point is that a hazard ratio is not an absolute effect. It does not tell a reader how many more people are alive at a given time.

Reference group and direction

A hazard ratio compares a group with a reference, and it is meaningless without both. In this dataset sex is coded 1 and 2 and enters the model as a number, so the “per unit” ratio compares code 2 (women) with code 1 (men). Recode it and the ratio inverts. The men-versus-women ratio is 1 divided by 0.575, about 1.74, with the interval inverted the same way: 1.25 to 2.41. It is the same finding written the other way, and neither version is more correct.

Which direction to report is a communication choice. Put the comparison first that your question names, say the reference in the sentence, and use the same direction in the table, the text and the figure. If the reference is a category with very few units, the interval will be wide whichever way round you write it.

The scale of a continuous predictor

For a numeric predictor the hazard ratio is per one unit of whatever the column holds, and the model assumes each unit multiplies the hazard by the same amount (Bradburn and colleagues 2003). The age row says 1.011 per year. On its own that looks like nothing. Over ten years the multiplication compounds: 1.011 raised to the tenth power is about 1.117, with the interval limits 0.993 and 1.030 giving 0.931 to 1.340. The estimate, the interval and the question are the same; only the unit changed, so the p-value (0.232) did not.

The ECOG score works the same way. 1.590 per point means the model’s estimated hazard for a score of 2 is 1.590 squared, about 2.53 times that for a score of 0 (interval 1.62 to 3.95), if each step really multiplies the hazard by the same factor. The compounding is only as good as that straight-line assumption. In these data only one person has a score of 3, so the upper end of the scale rests on little evidence.

Choose the unit before you look at the result. A per-year ratio of 1.011 and a per-decade ratio of 1.117 are the same finding, but the second is the one a reader can judge. Say the unit in the table header, every time, and do not compare the sizes of ratios on different scales: a per-point ECOG ratio and a per-year age ratio are not comparable until they are put on a common scale, such as per standard deviation.

The interval and the p-value

The 95% interval for the ECOG ratio, 1.273 to 1.986, is built on the log-hazard scale and then exponentiated, which is why it is not symmetric around 1.590. Read it as the range of ratios the data are reasonably compatible with, given the model. It does not say there is a 95% probability that the true ratio lies inside it. For the wording, see p-values and confidence intervals.

  • Does it include 1? A ratio of 1 means no difference in rates. The ECOG and sex intervals exclude 1. The age interval, 0.993 to 1.030, includes it, so the data cannot separate no association from a modest one.
  • How wide is it? The sex interval runs from a hazard about 41% as high to about 80% as high, which is a wide range of practical meanings behind one significant result. The precision comes from the number of events, 164, not the 227 people.
  • What does the p-value add? Only a measure of compatibility with a ratio of exactly 1. The sex coefficient has a Wald p of 0.00099, and the likelihood ratio test for the same term gives 11.44 on 1 degree of freedom (p = 0.0007), which tells the same story. A small p is not a large effect, and a large p is not “no effect”.

When proportional hazards affects how you read the number

A Cox model returns one hazard ratio per term, and that is a fair summary only if the ratio is roughly constant over follow-up. When it is not, the single number is a weighted average of an effect that changes over time, and the weights depend on how many events happen when, which is not something you chose (Hernán 2010; Stensrud and Hernán 2020). The practical consequence for reading is this: a hazard ratio of 0.575 reported without a check could hide a gap that is large early and gone later.

The engine’s check, a test of scaled Schoenfeld residuals, found no evidence against proportional hazards for this model (global p = 0.216). That is as much as such a test can say. It does not prove the hazards are proportional, and with few events it has little power. How to run the check, plot the residuals and respond when it fails is covered in the checking proportional hazards section of the Kaplan-Meier and Cox regression guide.

A second reading issue sits beside it. Each moment’s comparison is among those still event-free, so even in a randomised study the groups become less alike over time, which makes a hazard ratio hard to treat as a simple causal effect (Hernán 2010). In an observational dataset such as this one, adjustment for age and performance score does not remove that, and does not remove confounding by anything not in the model. Describe the result as an association.

Hazard ratio, median survival and absolute differences

A hazard ratio is one summary. Readers often want a second one on the time scale. The Kaplan-Meier companion run gives median survival, the time by which half the group has died: 270 days for men (95% CI 212 to 310) and 426 days for women (348 to 550), among 228 people with 165 deaths. The two summaries describe the same data without being interchangeable.

  • The ratio of the medians is 426 divided by 270, about 1.58. The inverse of the unadjusted hazard ratio, 1 divided by 0.588, is about 1.70. They differ because turning a hazard ratio into a ratio of times needs the shape of the hazard over time. Only when the hazard is constant (an exponential model) does the inverse of the hazard ratio equal the ratio of medians; under a Weibull model it is the hazard ratio raised to minus one over the shape, and in general no fixed conversion exists. Do not write “women survived 1.7 times as long” from a hazard ratio.
  • A median can be “not reached” when fewer than half the group has had an event, in which case only the hazard ratio is available.
  • A difference between medians (here 156 days) says nothing about the early or the late follow-up. Curves can differ a lot in one part and not at all in another.

The honest report puts the three together: the hazard ratio with its interval for the size of the difference in rates, the median survival with intervals per group for the time scale, and the survival curves, ideally with the number still at risk, for the absolute picture at any time a reader cares about. Restricted mean survival time is a further option when proportional hazards is in doubt (Royston and Parmar 2013).

How to write it up

State the model, the reference, the unit and the number of events, then give the estimate with its interval. An example for this analysis:

In a Cox model of 227 people (164 deaths; one person excluded for a missing performance score), women had a lower hazard of death than men (hazard ratio 0.575, 95% CI 0.414 to 0.799), adjusting for ECOG score and age. Each one-point higher ECOG score was associated with a higher hazard (hazard ratio 1.590, 95% CI 1.273 to 1.986). Age was not clearly associated (hazard ratio 1.117 per 10 years, 95% CI 0.931 to 1.340). Schoenfeld residual tests did not detect a departure from proportional hazards (global p = 0.216). Median survival was 270 days in men (95% CI 212 to 310) and 426 days in women (348 to 550).

Check each of these before you submit:

  1. The reference group is named, and the direction is the same in text and table.
  2. The unit of every continuous predictor is in the table header.
  3. Events are reported, not only units.
  4. Every ratio has an interval, and the text does not call a ratio “significant” without it.
  5. No sentence turns a hazard ratio into “times more likely”, “times as many” or “times as long”.
  6. The adjustment set is listed, and the language is associational unless the design supports a causal one.
  7. The proportional hazards check, and what it showed, is stated.

For general conventions on presenting estimates, see reporting statistics in APA style.

Rerunning the example

The example is reproducible: the downloadable script reruns the Cox model on the public dataset with a fixed seed and recomputes the recorded hazard ratios. The Kaplan-Meier medians come from a companion run on the same data. Both were produced by the same engine that Celeus uses, so you can compare your own software’s output with them. The inverted, per-decade and per-two-point ratios, the survival-curve illustration and the median ratios in this post are arithmetic on the recorded output, not engine output, so the script does not print them.

Worked example

Data: Loprinzi CL, Laurie JA, Wieand HS, Krook JE, Novotny PJ, Kugler JW, et al. (1994). Prospective evaluation of prognostic variables from patient-completed questionnaires. Journal of Clinical Oncology 12(3):601-607. https://doi.org/10.1200/JCO.1994.12.3.601. Seed: 20261022.

Run on Celeus engine 0.31.1, seed 20261022, public data.

Output

# Results

- Test: Cox proportional-hazards regression
- n: 227
- statistic: -3.294
- p-value: < 0.001
- effect size: hazard ratio = 0.5754 (95% CI 0.4142 to 0.7994)
- 95% CI: [0.4142, 0.7994]
- rows used: 227 of 228 (1 dropped)
- seed: 20261022

## Assumption checks
- proportional hazards (cox.zph): passed=TRUE (no evidence against proportional hazards)
- events per variable: passed=TRUE (at or above the rule-of-thumb floor (a convention, not a guarantee of a stable model))

## Term tests
| Term | Test | Statistic | df | Residual df | p-value |
|---|---|---|---|---|---|
| sex | LR | 11.44 | 1 | - | < 0.001 |
| ph.ecog | LR | 16.62 | 1 | - | < 0.001 |
| age | LR | 1.447 | 1 | - | 0.229 |

## Power
- Power is not calculated for this test.
R script
# Celeus - reproduce.R  (run from this package folder; bundled data in data/)
# Test: Cox proportional-hazards regression  |  engine 0.31.1  |  catalog c39-d3cd
# Research context: not provided for this run.
# Reproduces the recorded result deterministically.

set.seed(20261022)
.data_path <- "data/hazard-ratio.csv"
if (!file.exists(.data_path)) stop("Run reproduce.R from the package folder (the bundled data is in data/).")
data <- readr::read_csv(.data_path, show_col_types = FALSE)  # needs the readr package
clean_cells <- function (df) 
{
    ctrl_collapse <- "[\r\n\t\v\f]+"
    zero_width_chars <- intToUtf8(c(8203L, 65279L), multiple = TRUE)
    uni_space_chars <- intToUtf8(c(160L, 8239L, 8199L), multiple = TRUE)
    clean_text <- function(x) {
        out <- x
        for (ch in zero_width_chars) out <- gsub(ch, "", out, 
            fixed = TRUE)
        out <- gsub(ctrl_collapse, " ", out)
        for (ch in uni_space_chars) out <- gsub(ch, " ", out, 
            fixed = TRUE)
        trimws(gsub(" +", " ", out))
    }
    changed_cols <- character(0)
    cells_cleaned <- 0L
    retyped <- character(0)
    for (j in seq_along(df)) {
        col <- df[[j]]
        if (!is.character(col)) 
            next
        cleaned <- clean_text(col)
        n_changed <- sum(!is.na(col) & !is.na(cleaned) & col != 
            cleaned, na.rm = TRUE)
        if (n_changed > 0L) {
            changed_cols <- c(changed_cols, names(df)[j])
            cells_cleaned <- cells_cleaned + n_changed
        }
        df[[j]] <- cleaned
        non_blank <- cleaned[!is.na(cleaned) & nzchar(cleaned)]
        if (length(non_blank) && all(grepl("^[+-]?(0|[1-9][0-9]*)([.][0-9]+)?$", 
            non_blank))) {
            parsed <- suppressWarnings(as.numeric(cleaned))
            was_blank <- is.na(cleaned) | !nzchar(cleaned)
            lost <- (is.na(parsed) | is.infinite(parsed)) & !was_blank
            if (!any(lost)) {
                finite <- parsed[!is.na(parsed)]
                all_whole <- all(finite == floor(finite))
                in_range <- all(abs(finite) <= .Machine$integer.max)
                df[[j]] <- if (all_whole && in_range) 
                  as.integer(parsed)
                else parsed
                retyped <- c(retyped, names(df)[j])
            }
        }
    }
    names(df) <- clean_text(names(df))
    if (length(changed_cols)) {
        attr(df, "ingest_clean_columns") <- changed_cols
        attr(df, "ingest_clean_cells_cleaned") <- cells_cleaned
    }
    if (length(retyped)) 
        attr(df, "ingest_clean_retyped") <- retyped
    df
}
data <- clean_cells(data)
# Complete-case analysis: drop rows missing any analysis value.
data[["status"]] <- as.integer(factor(data[["status"]], levels = c("1", "2"))) - 1L
.acols <- c("sex", "ph.ecog", "age", "time", "status")
data <- data[stats::complete.cases(data[, .acols, drop = FALSE]), , drop = FALSE]
result <- { .fit <- survival::coxph(survival::Surv(`time`, `status`) ~ `sex` + `ph.ecog` + `age`, data = data); list(summary = summary(.fit), ph = survival::cox.zph(.fit), term_tests = stats::drop1(.fit, test = "Chisq")) }
print(result)

Common questions

What does a hazard ratio of 2 mean?

At any moment, among units still at risk, the event rate in the comparison group is estimated to be twice the rate in the reference group, after adjusting for the other terms. It does not say twice as many units have the event, or that the event comes twice as fast.

Is a hazard ratio the same as a risk ratio?

No. A risk ratio compares the proportion who have had the event by a fixed time. A hazard ratio compares instantaneous rates among those still event-free. The two point the same way but differ in size, and the gap grows as the event becomes common.

How do I interpret a hazard ratio below 1?

Subtract it from 1 and read the result as a percentage lower hazard. A ratio of 0.575 means an estimated hazard 42.5% lower than the reference group. Always say which group is the reference, because swapping them turns 0.575 into 1.74.

Does a significant hazard ratio mean a large effect?

No. The p-value says how compatible the data are with a ratio of 1, not how large the ratio is. Read the size from the estimate and judge the plausible range from the confidence interval. A narrow interval around 1.05 can be significant and small.

Can I turn a hazard ratio into a difference in survival time?

Not from the ratio alone. You need the baseline survival curve, or a model that works on the time scale. With proportional hazards, the survival curve of one group is the other's raised to the power of the ratio, so the absolute gap changes over follow-up.

Sources

  1. Cox DR (1972). Regression models and life-tables. Journal of the Royal Statistical Society: Series B (Methodological) 34(2):187-202. doi:10.1111/j.2517-6161.1972.tb00899.x
  2. Spruance SL, Reid JE, Grace M, Samore M (2004). Hazard ratio in clinical trials. Antimicrobial Agents and Chemotherapy 48(8):2787-2792. doi:10.1128/AAC.48.8.2787-2792.2004
  3. Hernán MA (2010). The hazards of hazard ratios. Epidemiology 21(1):13-15. doi:10.1097/EDE.0b013e3181c1ea43
  4. Bradburn MJ, Clark TG, Love SB, Altman DG (2003). Survival analysis part II: multivariate data analysis, an introduction to concepts and methods. British Journal of Cancer 89(3):431-436. doi:10.1038/sj.bjc.6601119
  5. Stensrud MJ, Hernán MA (2020). Why test for proportional hazards? JAMA 323(14):1401-1402. doi:10.1001/jama.2020.1267
  6. Royston P, Parmar MKB (2013). Restricted mean survival time: an alternative to the hazard ratio for the design and analysis of randomized trials with a time-to-event outcome. BMC Medical Research Methodology 13:152. doi:10.1186/1471-2288-13-152

Methods discussed

Try it on your own data

Upload a dataset and Celeus suggests a method, checks its assumptions, runs it in R, and gives you the script to rerun it.

Try it in Celeus