Courbe de survie de Kaplan-Meier en R : estimer et tracer

Estimez les probabilités de survie avec survfit, lisez la survie médiane et son IC à 95 %, et tracez la courbe de Kaplan-Meier signature de survminer — table des effectifs à risque, bandes de confiance et p-value du log-rank sur les données de cancer du poumon

Apprenez l’estimation de Kaplan-Meier en R avec les packages survival et survminer. Construisez l’objet Surv(time, status), estimez les courbes de survie avec survfit sur les données de cancer du poumon NCCTG, lisez la survie médiane et son intervalle de confiance à 95 %, interprétez la probabilité de survie à un instant donné, et tracez le ggsurvplot prêt à publier avec table des effectifs à risque, bandes de confiance, lignes de médiane et p-value du log-rank.

Date de publication

25 juin 2026

Modifié

11 juillet 2026

AstucePoints clés
  • L’estimation de Kaplan-Meier est la méthode non paramétrique de référence pour estimer et tracer une courbe de survie — la probabilité de survivre au-delà de chaque instant — à partir de données comportant de la censure (patients encore en vie, ou perdus de vue, à la fin de l’étude).
  • Estimez-la avec survfit(Surv(time, status) ~ group, data) ; l’affichage vous donne la survie médiane et son intervalle de confiance à 95 % par groupe.
  • Sur les données de cancer du poumon, la survie médiane est de 270 jours pour les hommes et de 426 jours pour les femmes — un net avantage de survie pour les femmes que le log-rank confirme (p = 0.001).
  • Tracez la courbe signature avec ggsurvplot() de survminer : marches de survie + table des effectifs à risque + bandes de confiance + lignes de médiane + la p-value du log-rank, le tout sur un seul panneau prêt à publier (jamais un simple plot()).
  • KM décrit et compare la survie entre groupes catégoriels ; pour ajuster sur des covariables ou utiliser un prédicteur continu, passez au modèle de Cox.

Introduction

Imaginez une étude sur le cancer du poumon : vous suivez des patients pendant des mois, certains décèdent durant le suivi, et d’autres sont encore en vie à la clôture de l’étude — vous n’observez jamais leur événement. Vous voulez une réponse simple et honnête à deux questions : quelle fraction de patients survit au-delà d’un instant donné, et la survie diffère-t-elle entre groupes (ici, hommes vs femmes) ?

Vous ne pouvez pas simplement faire la moyenne des durées de survie — cela jetterait chaque patient encore en vie (sa vraie durée de survie est inconnue, on sait seulement qu’elle est plus longue que ce que vous avez observé). C’est la censure, et c’est la caractéristique déterminante des données de survie. La méthode qui la gère est l’estimateur de Kaplan-Meier (KM) (Kaplan & Meier, 1958) : une estimation non paramétrique de la probabilité de survie \(S(t)\) — la probabilité de survivre au-delà de l’instant \(t\) — construite un événement à la fois.

Kaplan-Meier est le point d’entrée vers toute l’analyse de survie. Utilisez-le pour :

  • décrire la survie dans un seul groupe (la courbe de survie globale et la survie médiane) ;
  • comparer la survie entre 2 groupes catégoriels ou plus visuellement, avec le log-rank pour la p-value formelle ;
  • préparer le terrain pour le modèle de Cox à risques proportionnels, qui ajuste sur plusieurs covariables à la fois.

Cette leçon estime les courbes KM en R avec survival (le moteur) et survminer (graphiques de qualité publication), sur le jeu de données classique du cancer du poumon NCCTG, afin que vous puissiez reproduire exactement les chiffres et la figure.

Les données : l’étude sur le cancer du poumon NCCTG

Nous utilisons lung, le jeu de données du North Central Cancer Treatment Group fourni avec le package survival — la survie de 228 patients atteints d’un cancer du poumon avancé. Chargez le package et regardez les premières lignes (le jeu de données s’attache automatiquement avec survival, vous référencez donc lung directement — pas besoin d’appel data()) :

library(survival)

head(lung)
  inst time status age sex ph.ecog ph.karno pat.karno meal.cal wt.loss
1    3  306      2  74   1       1       90       100     1175      NA
2    3  455      2  68   1       0       90        90     1225      15
3    3 1010      1  56   1       0       90        90       NA      15
4    5  210      2  57   1       1       90        60     1150      11
5    1  883      2  60   1       0      100        90       NA       0
6   12 1022      1  74   1       1       50        80      513       0

Les colonnes dont nous avons besoin :

  • time — la durée de survie (suivi) en jours.
  • status — le statut de censure : 1 = censuré (en vie au dernier suivi), 2 = décédé (l’événement).
  • sex1 = homme, 2 = femme.

L’objet Surv() — la réponse

La réponse en analyse de survie n’est pas un simple nombre mais une paire durée–événement : combien de temps le patient a été observé, et si l’événement (le décès) s’est réellement produit ou si l’observation a été censurée. Vous le construisez avec Surv(time, status). R lit automatiquement status codé 1 = censuré / 2 = événement ; un + après une durée marque un patient censuré (en vie lorsqu’il a été vu pour la dernière fois) :

library(survival)

head(Surv(lung$time, lung$status))
[1]  306   455  1010+  210   883  1022+

Lisez les premiers : 306 et 455 sont des décès ; 1010+ est censuré — ce patient était en vie à 1010 jours, on sait donc seulement que sa survie dépasse 1010 jours. Cet objet Surv() est le membre de gauche de toute formule de survie.

Estimer les courbes de survie : survfit()

Utilisez survfit() avec la réponse Surv(time, status) à gauche et la variable de groupe à droite. Ici, nous estimons la survie selon le sexe :

library(survival)

fit <- survfit(Surv(time, status) ~ sex, data = lung)
print(fit)
Call: survfit(formula = Surv(time, status) ~ sex, data = lung)

        n events median 0.95LCL 0.95UCL
sex=1 138    112    270     212     310
sex=2  90     53    426     348     550

Lisez l’affichage, ligne par ligne :

  • n — les patients de chaque groupe : 138 hommes (sex=1), 90 femmes (sex=2).
  • events — les décès observés : 112 hommes, 53 femmes. Les autres ont été censurés.
  • median — le chiffre phare : la survie médiane est de 270 jours pour les hommes et de 426 jours pour les femmes. La survie médiane est l’instant où la probabilité de survie \(S(t)\) chute pour la première fois à 0.5 (la moitié du groupe est décédée) — le résumé le plus rapporté d’une courbe de survie.
  • 0.95LCL / 0.95UCL — l’intervalle de confiance à 95 % de la médiane : 212–310 jours pour les hommes, 348–550 jours pour les femmes. Les deux intervalles se chevauchent à peine, suggérant une différence réelle — que le log-rank confirmera ci-dessous.

Les femmes survivent nettement plus longtemps que les hommes dans ces données.

Probabilité de survie à un instant donné

Une courbe de survie répond aussi à « quelle fraction est encore en vie à l’instant t ? » Passez les instants qui vous intéressent à summary() — ici, 180 et 360 jours (environ 6 et 12 mois) :

library(survival)

fit <- survfit(Surv(time, status) ~ sex, data = lung)
summary(fit, times = c(180, 360))
Call: survfit(formula = Surv(time, status) ~ sex, data = lung)

                sex=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
  180     89      49    0.644  0.0408        0.569        0.730
  360     37      34    0.355  0.0437        0.279        0.452

                sex=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
  180     71      14    0.842  0.0387        0.770        0.922
  360     33      20    0.560  0.0586        0.457        0.688

En clair : à 360 jours, la probabilité de survie estimée est de 0.36 (36 %) pour les hommes et 0.56 (56 %) pour les femmes, chacune assortie d’un intervalle de confiance à 95 % (lower 95% CI / upper 95% CI). Donc un an plus tard, environ un tiers des hommes mais plus de la moitié des femmes sont encore en vie — le même avantage de survie que les médianes montraient.

Visualiser : la courbe de Kaplan-Meier avec ggsurvplot()

Les chiffres sont précis, mais une courbe de Kaplan-Meier est la façon dont les résultats de survie se lisent. Utilisez ggsurvplot() de survminer — il trace les courbes de survie en escalier et ajoute tout ce dont un lecteur a besoin sur un seul panneau :

  • conf.int = TRUE — des bandes de confiance à 95 % ombrées autour de chaque courbe ;
  • risk.table = TRUE — le nombre de sujets à risque sous le graphique à chaque instant (pour que vous sachiez combien de données soutiennent la queue de courbe) ;
  • pval = TRUE — la p-value du log-rank comparant les courbes, imprimée sur le graphique ;
  • surv.median.line = "hv" — des repères de survie médiane en pointillés horizontaux + verticaux ;
  • palette = "jco" — une palette de revue adaptée au daltonisme.
library(survival)
library(survminer)

fit <- survfit(Surv(time, status) ~ sex, data = lung)

ggsurvplot(
  fit,
  data = lung,
  risk.table = TRUE,        # number at risk under the plot
  conf.int = TRUE,          # 95% confidence bands
  pval = TRUE,              # log-rank p-value on the plot
  surv.median.line = "hv",  # dashed median-survival guides
  palette = "jco",          # colourblind-safe journal palette
  legend.labs = c("Male", "Female"),
  legend.title = "Sex",
  xlab = "Time (days)",
  ylab = "Survival probability",
  ggtheme = theme_minimal()
)

A survminer Kaplan-Meier plot of survival by sex on the lung-cancer data. Two step-function survival curves descend from 1.0 over time, the female curve staying consistently above the male curve, each with a shaded 95% confidence band. Dashed median-survival lines mark 270 days for men and 426 days for women. The log-rank p-value (0.0013) is printed on the plot, and a risk table beneath shows the number of patients still at risk over time.

Comment la lire :

  • L’axe des y est la probabilité de survie (commence à 1.0 = tout le monde en vie) ; l’axe des x est le temps en jours. Chaque chute verticale est un décès ; chaque petite marque de tick est un patient censuré.
  • La courbe des femmes reste au-dessus de celle des hommes à chaque instant — une meilleure survie pour les femmes, du début à la fin.
  • Les lignes de médiane en pointillés rencontrent l’axe des x à 270 jours (hommes) et 426 jours (femmes) — les chiffres de survfit(), désormais sur le graphique.
  • La p-value du log-rank (0.0013) indique que la différence entre les courbes est statistiquement significative.
  • La table des effectifs à risque montre le nombre de sujets encore à risque diminuer au fil du temps — notez combien peu de patients restent dans la queue, ce qui explique pourquoi les bandes de confiance s’évasent tardivement (interprétez l’extrémité droite de toute courbe KM avec prudence).

La table de survie de Kaplan-Meier : summary(fit)

ggsurvplot() montre la courbe ; la table de survie donne l’estimation sous-jacente, étape par étape. summary(fit) renvoie, à chaque instant d’événement, le nombre de sujets à risque (n.risk), le nombre de décès (n.event), la probabilité de survie estimée (survival) et son intervalle de confiance. Elle est longue, alors regardez les premières lignes pour les hommes :

library(survival)

fit <- survfit(Surv(time, status) ~ sex, data = lung)
s <- summary(fit)

# The first few steps of the life table (one row per event time)
life_table <- data.frame(
  time    = s$time,
  n.risk  = s$n.risk,
  n.event = s$n.event,
  surv    = round(s$surv, 3),
  lower   = round(s$lower, 3),
  upper   = round(s$upper, 3),
  group   = s$strata
)
head(life_table, 8)
  time n.risk n.event  surv lower upper group
1   11    138       3 0.978 0.954 1.000 sex=1
2   12    135       1 0.971 0.943 0.999 sex=1
3   13    134       2 0.957 0.923 0.991 sex=1
4   15    132       1 0.949 0.913 0.987 sex=1
5   26    131       1 0.942 0.904 0.982 sex=1
6   30    130       1 0.935 0.894 0.977 sex=1
7   31    129       1 0.928 0.885 0.972 sex=1
8   53    128       2 0.913 0.867 0.961 sex=1

Chaque ligne est une marche de la courbe : la survie ne change qu’à un instant d’événement, chutant d’un facteur qui dépend du nombre de sujets à risque. C’est l’estimation produit-limite tracée ci-dessus — la table et la figure en sont deux vues.

Comparer les groupes formellement : le log-rank

La courbe KM suggère que les femmes survivent plus longtemps ; le log-rank décide si cet écart est réel. C’est le test non paramétrique de référence pour comparer des courbes de survie, avec H₀ = aucune différence de survie entre les groupes. Le pval = TRUE que vous avez vu sur le graphique est exactement ce test. Calculez-le directement avec survdiff() :

library(survival)

survdiff(Surv(time, status) ~ sex, data = lung)
Call:
survdiff(formula = Surv(time, status) ~ sex, data = lung)

        N Observed Expected (O-E)^2/E (O-E)^2/V
sex=1 138      112     91.6      4.55      10.3
sex=2  90       53     73.4      5.68      10.3

 Chisq= 10.3  on 1 degrees of freedom, p= 0.001 

Le test donne χ² = 10.3 à 1 degré de liberté, p = 0.001 — la différence de survie entre les hommes et les femmes est statistiquement significative. Le log-rank répond à « les courbes diffèrent-elles ? » mais ne donne aucune taille d’effet et ne peut pas gérer des prédicteurs continus ni ajuster sur des facteurs de confusion — pour cela, il vous faut le modèle de Cox.

NoteDe la description à la modélisation de la survie
  • Décrire / comparer des groupes catégoriels → courbes de Kaplan-Meier + le log-rank (cette leçon) — une courbe de survie et une p-value.
  • Estimer une taille d’effet, utiliser un prédicteur continu, ou ajuster sur plusieurs covariables à la fois → le modèle de Cox à risques proportionnels — un hazard ratio par facteur.

Rapport

La survie a été estimée par la méthode de Kaplan-Meier sur les données de cancer du poumon NCCTG (n = 228, 165 décès). La survie globale médiane était de 270 jours (IC à 95 % 212–310) pour les hommes et de 426 jours (IC à 95 % 348–550) pour les femmes. La survie à un an était de 36 % (hommes) contre 56 % (femmes). La différence de survie entre les sexes était statistiquement significative (log-rank χ²(1) = 10.3, p = 0.001).

La probabilité de survie à l’instant d’événement \(t_i\) se construit récursivement à partir de la probabilité à l’instant d’événement précédent, multipliée par la probabilité conditionnelle de survivre à l’instant courant — l’estimateur produit-limite :

\[ S(t_i) = S(t_{i-1}) \left( 1 - \frac{d_i}{n_i} \right) \]

\(n_i\) est le nombre de patients à risque juste avant \(t_i\), \(d_i\) est le nombre d’événements (décès) à \(t_i\), et \(S(t_0) = 1\). Comme la courbe ne change qu’à un instant d’événement, \(S(t)\) est une fonction en escalier : elle reste plate entre les événements et chute à chacun. Les patients censurés quittent l’ensemble de sujets à risque sans provoquer de chute — ils réduisent simplement \(n_i\) pour les instants ultérieurs, et c’est ainsi que Kaplan-Meier utilise l’information de chaque patient jusqu’au moment où il est perdu, au lieu de l’écarter. L’intervalle de confiance autour de \(S(t)\) provient de la formule de Greenwood pour son erreur standard.

Quelle méthode, et quand ?

AstuceChoisir votre méthode de survie
  • Décrire la survie dans un seul groupe (courbe, survie médiane, survie à l’instant t) → estimation de Kaplan-Meier (cette leçon).
  • Comparer la survie entre 2 groupes catégoriels ou plus avec une p-value → log-rank.
  • Modéliser l’effet d’une ou plusieurs covariables (catégorielles ou continues), ajustées les unes pour les autres, avec un hazard ratio → Cox à risques proportionnels.
  • Nouveau venu sur les concepts (censure, fonctions de risque vs de survie) → qu’est-ce que l’analyse de survie ?.

Essayez en direct

Estimez les courbes vous-même — remplacez sex par une autre variable de groupe, ou changez les instants que vous résumez. Le bac à sable démarre au premier Run.

🟢 Avec un agent IA

Demandez à Prova « estime les courbes de survie de Kaplan-Meier sur mes données, donne-moi la survie médiane avec les IC à 95 %, et trace un ggsurvplot prêt à publier avec la table des effectifs à risque et la p-value du log-rank » — elle répond avec du code survival + survminer que vous pouvez exécuter sur vos propres données. The runtime is the judge. Demander à Prova →

Problèmes courants

La survie médiane vaut NA (« non atteinte »). Si moins de la moitié des patients d’un groupe subissent l’événement, la courbe de survie ne chute jamais à 0.5, donc la médiane est indéfinie — R affiche NA. C’est normal avec une censure importante ou un suivi court. Rapportez un autre quantile (p. ex. le 25e percentile via quantile(fit, probs = 0.25)) ou la probabilité de survie à un instant fixe à la place.

Vos courbes se croisent. Kaplan-Meier et le log-rank supposent que les courbes se séparent dans une direction cohérente ; des courbes qui se croisent signifient qu’un groupe fait mieux tôt et moins bien plus tard (ou l’inverse). Le log-rank perd de la puissance ici et peut manquer une différence réelle — envisagez un test pondéré (Fleming-Harrington) ou rapportez la survie à des instants précis. Des courbes qui se croisent signalent aussi que l’hypothèse des risques proportionnels d’un modèle de Cox ultérieur est probablement violée.

Vous avez oublié les ticks de censure, ou lu la queue trop littéralement. Les petites marques de tick sur la courbe sont des patients censurés, pas des événements — ne les confondez pas avec des chutes. Et comme peu de patients restent à risque tard dans le suivi (vérifiez la table des effectifs à risque), l’extrémité droite de la courbe est instable et sa bande de confiance est large ; évitez les affirmations fortes sur la survie à long terme à partir d’une queue clairsemée.

Questions fréquentes

Il estime la probabilité de survie au fil du temps — la probabilité de survivre au-delà de chaque instant — à partir de données comportant de la censure. Utilisez-le pour décrire la survie dans un groupe (la courbe de survie et la survie médiane), et pour comparer visuellement la survie entre groupes catégoriels, associé au log-rank pour la p-value formelle.

La survie médiane est l’instant où la probabilité de survie \(S(t)\) atteint pour la première fois 0.5 — la moitié du groupe a subi l’événement. Sur le graphique, tracez une ligne horizontale à 0.5 et lisez où elle croise chaque courbe (surv.median.line = "hv" le fait pour vous) ; en R, l’affichage de survfit() la rapporte directement avec un intervalle de confiance à 95 %.

Parce que moins de la moitié des patients de ce groupe ont subi l’événement, donc la courbe de survie ne chute jamais à 0.5 et la médiane est indéfinie. Cela arrive avec une censure importante ou un suivi court. Rapportez un autre quantile (p. ex. le 25e percentile) ou la probabilité de survie à un instant fixe (summary(fit, times = …)) à la place.

La courbe de Kaplan-Meier estime et affiche la survie au fil du temps pour chaque groupe ; le log-rank teste si les courbes diffèrent, renvoyant une statistique du chi-deux et une p-value. KM relève de la description ; le log-rank relève de l’inférence. Ni l’un ni l’autre ne donne de taille d’effet ni ne gère de prédicteurs continus — pour cela, utilisez le modèle de Cox.

Deux : survival pour estimer les courbes (Surv(), survfit(), survdiff()) et survminer pour tracer le graphique prêt à publier (ggsurvplot() avec la table des effectifs à risque, les bandes de confiance, les lignes de médiane et la p-value du log-rank). Tous deux fournissent le jeu de données lung utilisé ici.

Testez vos connaissances

  1. Exécutez-le. Dans la cellule interactive ci-dessous, estimez les courbes de Kaplan-Meier pour l’échantillon global (une seule courbe, sans groupe) en remplissant le blanc par 1. Quelle est la survie médiane globale, et comment se compare-t-elle aux médianes par sexe (270 vs 426 jours) ?
  2. Interprétez. Une analyse KM rapporte une survie médiane de NA dans le groupe traitement mais de 280 jours dans le groupe témoin. En clair, que signifie le NA, et que devriez-vous rapporter à la place ?

Pour une courbe globale sans groupe, le membre de droite de la formule est 1. La colonne median de l’affichage donne la survie médiane globale ; comparez-la aux médianes par sexe.

fit <- survfit(Surv(time, status) ~ 1, data = lung)
print(fit)
#> n = 228, events = 165, median = 310 (95% CI 285-363)

La survie médiane globale est de 310 jours — entre les médianes des hommes (270) et des femmes (426), comme attendu lorsqu’on regroupe les deux groupes.

Pour la question 2 : une médiane de NA (« non atteinte ») signifie que moins de la moitié des patients du groupe traitement sont décédés, donc la courbe n’a jamais chuté à 0.5 — souvent un bon signe (meilleure survie). Ne la rapportez pas comme une valeur manquante ou un zéro ; rapportez plutôt la probabilité de survie à un instant fixe, ou un quantile inférieur (p. ex. le 25e percentile), et indiquez la proportion encore sans événement à la fin du suivi.

AstuceVérification rapide

Sur une courbe de Kaplan-Meier, que représente une petite marque de tick sur une courbe de survie ?

Un patient censuré — quelqu’un qui était encore en vie (sans événement) à cet instant mais a ensuite quitté l’étude (fin de suivi ou perdu de vue). Un tick n’est pas un événement ; les événements sont les chutes verticales de la courbe. Les patients censurés réduisent le nombre de sujets à risque pour les instants ultérieurs mais ne font pas descendre la courbe d’un cran.

Conclusion

Vous savez maintenant réaliser une estimation de Kaplan-Meier en R : construire la réponse Surv(time, status), estimer les courbes de survie avec survfit(), lire la survie médiane et son IC à 95 % ainsi que la probabilité de survie à n’importe quel instant, et tracer le ggsurvplot() signature de survminer — table des effectifs à risque, bandes de confiance, lignes de médiane et p-value du log-rank sur un seul panneau prêt à publier. Sur les données de cancer du poumon, la survie médiane était de 270 jours pour les hommes contre 426 pour les femmes, une différence que le log-rank a confirmée (p = 0.001). Kaplan-Meier décrit et compare la survie entre groupes catégoriels ; lorsque vous avez besoin d’une taille d’effet, d’un prédicteur continu, ou d’un ajustement sur plusieurs facteurs à la fois, le modèle de Cox est l’étape suivante.

Leçons connexes

Cette page vous a-t-elle été utile ?

Prouvez que vous savez le faire. Maîtrisez toute la série Analyse de survie en R — suivez votre parcours, construisez des projets et obtenez un certificat.

Commencer gratuitement →

Passez à Pro — Prova illimité sur vos propres données et un certificat vérifiable qui atteste la compétence.

dès 15 $/mois facturé annuellement

Passer à Pro →

✓ Vous êtes Pro — continuez. The runtime is the judge.

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN
Note

Chaque résultat de cette page a été produit par le code montré, exécuté au moment du build contre un environnement R figé — modifiez n’importe quel bloc et faites Run pour le reproduire vous-même.

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Courbe de survie de Kaplan-Meier en R : estimer et tracer},
  date = {2026-06-25},
  url = {https://www.datanovia.com/learn/biostatistics/survival-analysis/kaplan-meier-estimation},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Courbe de survie de Kaplan-Meier en R : estimer et tracer.” 2026. June 25. https://www.datanovia.com/learn/biostatistics/survival-analysis/kaplan-meier-estimation.