The Log-Rank Test (also known as the Mantel-Cox test) is a non-parametric hypothesis test used to compare survival distributions between two or more groups. It tests the null hypothesis that there is no difference in survival between groups, making it essential for comparing treatment effects in clinical trials and other time-to-event studies.
💡 Pro Tip: Your data must include a time column (time to event or censoring), an event column (1 = event occurred, 0 = censored), and a group column (to identify which group each observation belongs to). The test requires at least 2 groups. For survival curve estimation without group comparison, use Kaplan-Meier Estimator. For modeling multiple covariates, consider Cox Proportional Hazards Model.
Ready to compare survival curves between groups? (clinical trial comparing Treatment vs. Control) to see the Log-Rank Test in action, or upload your own time-to-event data with group labels.
Time to event or censoring
1 = event, 0 = censored
Required for group comparison
The Log-Rank Test (also called the Mantel-Cox test or Mantel-Haenszel test) is a non-parametric hypothesis test that compares the survival distributions of two or more groups. It tests whether there are significant differences in the survival experiences between groups by comparing the observed number of events in each group to what would be expected if survival was the same across all groups.
The Log-Rank test statistic:
where is the observed number of events in group , is the expected number of events, and is the number of groups. The statistic follows a chi-squared distribution with degrees of freedom.
| Time | Event | Group | Meaning |
|---|---|---|---|
| 5 | 1 | Treatment | Event occurred |
| 8 | 0 | Treatment | Censored |
| 12 | 1 | Control | Event occurred |
| 15 | 0 | Control | Censored |
| 18 | 1 | Treatment | Event occurred |
Time: Any non-negative number (days, months, years, etc.)
Event: 1 = event occurred, 0 = censored
Group: Any text labels to identify groups (e.g., Treatment, Control, Drug A, Drug B)
| Time | Event | Group |
|---|---|---|
| 5 | yes | Treatment |
| 8 | no | Control |
❌ Event must be 1 (event) or 0 (censored)
| Time | Event | Group |
|---|---|---|
| -5 | 1 | Treatment |
| 8 | 0 | Control |
❌ Time values must be zero or positive
| Time | Event | Group |
|---|---|---|
| 5 | — | Treatment |
| 8 | — | Control |
❌ Missing Event column
1. Compares at each event time: At each time an event occurs, counts how many events happened in each group
2. Expected vs Observed: Calculates how many events we'd expect if groups were identical, then compares to actual observations
3. Chi-squared statistic: Sums up differences across all event times: Σ(Observed - Expected)² / Expected
4. p-value: If curves diverge significantly (like above), p-value is small → groups differ significantly
Use the Log-Rank Test when:
library(survival)
library(survminer)
library(tidyverse)
# Clinical trial data: time to recovery (days), event (1=recovered, 0=censored)
data <- tibble(
time = c(5, 8, 12, 15, 18, 23, 25, 30, 35, 40, 45, 48, 50, 55, 60),
event = c(1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1),
group = c('Treatment', 'Treatment', 'Treatment', 'Treatment', 'Treatment',
'Treatment', 'Treatment', 'Treatment', 'Control', 'Control',
'Control', 'Control', 'Control', 'Control', 'Control')
)
# Perform Log-Rank Test (also known as Mantel-Cox test)
logrank_result <- survdiff(Surv(time, event) ~ group, data = data)
# Print results
print(logrank_result)
# Extract key statistics
chi_squared <- logrank_result$chisq
df <- length(logrank_result$n) - 1
p_value <- 1 - pchisq(chi_squared, df)
cat("\nLog-Rank Test Results:\n")
cat("Chi-squared statistic:", round(chi_squared, 3), "\n")
cat("Degrees of freedom:", df, "\n")
cat("p-value:", format.pval(p_value, digits = 3), "\n")
# Visualize survival curves by group
km_fit <- survfit(Surv(time, event) ~ group, data = data)
ggsurvplot(km_fit,
conf.int = TRUE,
pval = TRUE,
risk.table = TRUE,
xlab = "Time (days)",
ylab = "Survival Probability",
title = "Survival Curves by Group",
legend.title = "Group",
legend.labs = levels(factor(data$group)))import numpy as np
import pandas as pd
from lifelines import KaplanMeierFitter
from lifelines.statistics import logrank_test, multivariate_logrank_test
import matplotlib.pyplot as plt
# Clinical trial data: time to recovery (days), event (1=recovered, 0=censored)
data = pd.DataFrame({
'time': [5, 8, 12, 15, 18, 23, 25, 30, 35, 40, 45, 48, 50, 55, 60],
'event': [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1],
'group': ['Treatment', 'Treatment', 'Treatment', 'Treatment', 'Treatment',
'Treatment', 'Treatment', 'Treatment', 'Control', 'Control',
'Control', 'Control', 'Control', 'Control', 'Control']
})
# Log-Rank Test for two groups
treatment_data = data[data['group'] == 'Treatment']
control_data = data[data['group'] == 'Control']
results = logrank_test(
treatment_data['time'], control_data['time'],
treatment_data['event'], control_data['event']
)
print("Log-Rank Test Results:")
print(f"Test statistic: {results.test_statistic:.3f}")
print(f"p-value: {results.p_value:.4f}")
print(results.summary)
# For more than 2 groups, use multivariate_logrank_test
# result = multivariate_logrank_test(data['time'], data['group'], data['event'])
# print(result.summary)
# Plot survival curves by group
fig, ax = plt.subplots(figsize=(10, 6))
for group in data['group'].unique():
group_data = data[data['group'] == group]
kmf = KaplanMeierFitter()
kmf.fit(
durations=group_data['time'],
event_observed=group_data['event'],
label=group
)
kmf.plot_survival_function(ax=ax, ci_show=True)
plt.title(f'Survival Curves by Group (p={results.p_value:.4f})')
plt.xlabel('Time (days)')
plt.ylabel('Survival Probability')
plt.ylim(0, 1)
plt.grid(True, alpha=0.3)
plt.legend()
plt.show()Get survival curves & median survival
Test if groups differ significantly
Adjust for covariates & hazard ratios
The Log-Rank Test (also known as the Mantel-Cox test) is a non-parametric hypothesis test used to compare survival distributions between two or more groups. It tests the null hypothesis that there is no difference in survival between groups, making it essential for comparing treatment effects in clinical trials and other time-to-event studies.
💡 Pro Tip: Your data must include a time column (time to event or censoring), an event column (1 = event occurred, 0 = censored), and a group column (to identify which group each observation belongs to). The test requires at least 2 groups. For survival curve estimation without group comparison, use Kaplan-Meier Estimator. For modeling multiple covariates, consider Cox Proportional Hazards Model.
Ready to compare survival curves between groups? (clinical trial comparing Treatment vs. Control) to see the Log-Rank Test in action, or upload your own time-to-event data with group labels.
Time to event or censoring
1 = event, 0 = censored
Required for group comparison
The Log-Rank Test (also called the Mantel-Cox test or Mantel-Haenszel test) is a non-parametric hypothesis test that compares the survival distributions of two or more groups. It tests whether there are significant differences in the survival experiences between groups by comparing the observed number of events in each group to what would be expected if survival was the same across all groups.
The Log-Rank test statistic:
where is the observed number of events in group , is the expected number of events, and is the number of groups. The statistic follows a chi-squared distribution with degrees of freedom.
| Time | Event | Group | Meaning |
|---|---|---|---|
| 5 | 1 | Treatment | Event occurred |
| 8 | 0 | Treatment | Censored |
| 12 | 1 | Control | Event occurred |
| 15 | 0 | Control | Censored |
| 18 | 1 | Treatment | Event occurred |
Time: Any non-negative number (days, months, years, etc.)
Event: 1 = event occurred, 0 = censored
Group: Any text labels to identify groups (e.g., Treatment, Control, Drug A, Drug B)
| Time | Event | Group |
|---|---|---|
| 5 | yes | Treatment |
| 8 | no | Control |
❌ Event must be 1 (event) or 0 (censored)
| Time | Event | Group |
|---|---|---|
| -5 | 1 | Treatment |
| 8 | 0 | Control |
❌ Time values must be zero or positive
| Time | Event | Group |
|---|---|---|
| 5 | — | Treatment |
| 8 | — | Control |
❌ Missing Event column
1. Compares at each event time: At each time an event occurs, counts how many events happened in each group
2. Expected vs Observed: Calculates how many events we'd expect if groups were identical, then compares to actual observations
3. Chi-squared statistic: Sums up differences across all event times: Σ(Observed - Expected)² / Expected
4. p-value: If curves diverge significantly (like above), p-value is small → groups differ significantly
Use the Log-Rank Test when:
library(survival)
library(survminer)
library(tidyverse)
# Clinical trial data: time to recovery (days), event (1=recovered, 0=censored)
data <- tibble(
time = c(5, 8, 12, 15, 18, 23, 25, 30, 35, 40, 45, 48, 50, 55, 60),
event = c(1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1),
group = c('Treatment', 'Treatment', 'Treatment', 'Treatment', 'Treatment',
'Treatment', 'Treatment', 'Treatment', 'Control', 'Control',
'Control', 'Control', 'Control', 'Control', 'Control')
)
# Perform Log-Rank Test (also known as Mantel-Cox test)
logrank_result <- survdiff(Surv(time, event) ~ group, data = data)
# Print results
print(logrank_result)
# Extract key statistics
chi_squared <- logrank_result$chisq
df <- length(logrank_result$n) - 1
p_value <- 1 - pchisq(chi_squared, df)
cat("\nLog-Rank Test Results:\n")
cat("Chi-squared statistic:", round(chi_squared, 3), "\n")
cat("Degrees of freedom:", df, "\n")
cat("p-value:", format.pval(p_value, digits = 3), "\n")
# Visualize survival curves by group
km_fit <- survfit(Surv(time, event) ~ group, data = data)
ggsurvplot(km_fit,
conf.int = TRUE,
pval = TRUE,
risk.table = TRUE,
xlab = "Time (days)",
ylab = "Survival Probability",
title = "Survival Curves by Group",
legend.title = "Group",
legend.labs = levels(factor(data$group)))import numpy as np
import pandas as pd
from lifelines import KaplanMeierFitter
from lifelines.statistics import logrank_test, multivariate_logrank_test
import matplotlib.pyplot as plt
# Clinical trial data: time to recovery (days), event (1=recovered, 0=censored)
data = pd.DataFrame({
'time': [5, 8, 12, 15, 18, 23, 25, 30, 35, 40, 45, 48, 50, 55, 60],
'event': [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1],
'group': ['Treatment', 'Treatment', 'Treatment', 'Treatment', 'Treatment',
'Treatment', 'Treatment', 'Treatment', 'Control', 'Control',
'Control', 'Control', 'Control', 'Control', 'Control']
})
# Log-Rank Test for two groups
treatment_data = data[data['group'] == 'Treatment']
control_data = data[data['group'] == 'Control']
results = logrank_test(
treatment_data['time'], control_data['time'],
treatment_data['event'], control_data['event']
)
print("Log-Rank Test Results:")
print(f"Test statistic: {results.test_statistic:.3f}")
print(f"p-value: {results.p_value:.4f}")
print(results.summary)
# For more than 2 groups, use multivariate_logrank_test
# result = multivariate_logrank_test(data['time'], data['group'], data['event'])
# print(result.summary)
# Plot survival curves by group
fig, ax = plt.subplots(figsize=(10, 6))
for group in data['group'].unique():
group_data = data[data['group'] == group]
kmf = KaplanMeierFitter()
kmf.fit(
durations=group_data['time'],
event_observed=group_data['event'],
label=group
)
kmf.plot_survival_function(ax=ax, ci_show=True)
plt.title(f'Survival Curves by Group (p={results.p_value:.4f})')
plt.xlabel('Time (days)')
plt.ylabel('Survival Probability')
plt.ylim(0, 1)
plt.grid(True, alpha=0.3)
plt.legend()
plt.show()Get survival curves & median survival
Test if groups differ significantly
Adjust for covariates & hazard ratios