Tester l’hypothèse des risques proportionnels en R (cox.zph, Schoenfeld)

Vérifiez si les hazard ratios de votre modèle de Cox sont constants au cours du temps — cox.zph, résidus de Schoenfeld mis à l’échelle avec ggcoxzph, diagnostics d’influence et de non-linéarité, et que faire quand l’hypothèse PH échoue

Validez un modèle de Cox à risques proportionnels en R. Testez l’hypothèse des risques proportionnels (PH) avec cox.zph et le graphique des résidus de Schoenfeld mis à l’échelle ggcoxzph, recherchez les observations influentes avec ggcoxdiagnostics (résidus dfbeta et déviance), testez la forme fonctionnelle des covariables continues avec les résidus de martingale, et apprenez les remèdes quand l’hypothèse PH est violée — stratification, coefficients dépendants du temps et interactions avec le temps.

Date de publication

25 juin 2026

Modifié

7 juillet 2026

AstucePoints clés
  • Le modèle de Cox repose sur une hypothèse : les risques proportionnels (PH) — le hazard ratio entre deux patients quelconques reste constant au cours du temps. Si l’effet d’une covariable grandit, diminue ou s’inverse au cours du suivi, le hazard ratio unique est trompeur et doit être corrigé.
  • Testez l’hypothèse PH avec cox.zph() — il corrèle les résidus de Schoenfeld mis à l’échelle de chaque covariable avec le temps. Non significatif (p ≥ 0.05) = l’hypothèse PH tient ; significatif (p < 0.05) = l’hypothèse PH est violée. Il rapporte un test par covariable et un test GLOBAL pour l’ensemble du modèle.
  • Visualisez-le avec ggcoxzph() de survminer — résidus de Schoenfeld mis à l’échelle en fonction du temps. Une ligne de lissage plate appuie l’hypothèse PH ; une tendance systématique signale une violation.
  • Vérifiez aussi les observations influentes (ggcoxdiagnostics(fit, type = "dfbeta") / "deviance") et la forme fonctionnelle des covariables continues (résidus de martingale via ggcoxfunctional()).
  • Quand l’hypothèse PH échoue, n’abandonnez pas le modèle — stratifiez la covariable fautive, ajoutez un coefficient dépendant du temps (tt()) ou une interaction avec le temps, ou utilisez un test log-rank pondéré.

Introduction

Vous avez ajusté un modèle de Cox à risques proportionnels sur vos données de survie et relevé les hazard ratios — le sexe féminin réduit le risque de décès d’environ 42 %, un score ECOG moins bon l’augmente d’environ 59 %. Des nombres nets, un forest plot soigné. Mais il y a un piège : chacun de ces hazard ratios suppose que l’effet est constant sur l’ensemble du suivi. C’est l’hypothèse des risques proportionnels (PH), et c’est la seule chose qu’un modèle de Cox peut mal estimer d’une façon qui invalide discrètement le résultat.

Imaginez un essai où un traitement aide tôt mais où son bénéfice s’estompe après un an (ou agit tardivement, comme le fait souvent l’immunothérapie). Les courbes de survie se croisent ou convergent — le hazard ratio n’est pas constant — et le HR unique que le modèle affiche est une moyenne temporelle trompeuse qui masque la véritable histoire. Utilisé à mauvais escient, un modèle de Cox donne des conclusions assurées mais fausses. Donc, avant de faire confiance à un hazard ratio, testez l’hypothèse qui l’a produit.

Cette leçon parcourt le flux de diagnostic complet d’un modèle de Cox en R, en utilisant survival (les tests) et survminer (les graphiques de diagnostic de qualité publication), sur le même modèle du cancer du poumon NCCTG de la leçon sur Cox. Vous apprendrez à :

  • tester les risques proportionnels avec cox.zph() et lire ses tests par covariable et global ;
  • tracer les résidus de Schoenfeld mis à l’échelle avec la figure emblématique ggcoxzph() ;
  • trouver les observations influentes avec ggcoxdiagnostics() (résidus dfbeta et déviance) ;
  • tester la forme fonctionnelle des covariables continues avec les résidus de martingale ;
  • et corriger une violation de l’hypothèse PH lorsque vous en trouvez une.
NoteCe que nous testons

Nous vérifions si le modèle de Cox est une représentation adéquate des données en examinant ses résidus :

  • Résidus de Schoenfeld → l’hypothèse des risques proportionnels (HR constant au cours du temps).
  • Résidus dfbeta / déviance → les observations influentes (quelques points qui faussent l’ajustement).
  • Résidus de martingale → la forme fonctionnelle des covariables continues (linéaire vs non linéaire).

H₀ (pour l’hypothèse PH) : le hazard ratio est constant au cours du temps (les résidus sont indépendants du temps). Hₐ : le hazard ratio change au cours du temps (une tendance dans les résidus). Un test significatif rejette l’hypothèse PH.

Les données et le modèle

Nous réutilisons lung, le jeu de données du North Central Cancer Treatment Group fourni avec le package survival (228 patients atteints d’un cancer du poumon avancé), et le même modèle de Cox multivarié de la leçon sur Cox : la survie sur l’âge, le sexe et le score de performance ECOG. Chargez le package — lung s’attache automatiquement — et ajustez le modèle :

library(survival)

res.cox <- coxph(Surv(time, status) ~ age + sex + ph.ecog, data = lung)
res.cox
Call:
coxph(formula = Surv(time, status) ~ age + sex + ph.ecog, data = lung)

             coef exp(coef)  se(coef)      z        p
age      0.011067  1.011128  0.009267  1.194 0.232416
sex     -0.552612  0.575445  0.167739 -3.294 0.000986
ph.ecog  0.463728  1.589991  0.113577  4.083 4.45e-05

Likelihood ratio test=30.5  on 3 df, p=1.083e-06
n= 227, number of events= 164 
   (1 observation effacée parce que manquante)

Un rappel du codage : status est 1 = censuré / 2 = décédé, sex est 1 = homme / 2 = femme, ph.ecog est le score de performance ECOG (0 = pleinement actif, plus élevé = plus altéré). C’est l’objet ajusté que nous soumettons maintenant à ses diagnostics.

Tester l’hypothèse des risques proportionnels avec cox.zph()

L’hypothèse PH peut être vérifiée avec un test statistique et un diagnostic graphique, tous deux construits sur les résidus de Schoenfeld mis à l’échelle. L’idée est simple : sous risques proportionnels, les résidus de Schoenfeld sont indépendants du temps. Un motif de résidus qui dérive avec le temps est la preuve que le hazard ratio n’est pas constant — c’est-à-dire que l’hypothèse PH est violée.

La fonction cox.zph() (du package survival) fait exactement cela. Pour chaque covariable, elle corrèle les résidus de Schoenfeld mis à l’échelle avec le temps (transformé), et elle ajoute un test GLOBAL pour le modèle dans son ensemble. Passez-lui l’objet coxph ajusté :

library(survival)

res.cox <- coxph(Surv(time, status) ~ age + sex + ph.ecog, data = lung)

test.ph <- cox.zph(res.cox)
test.ph
        chisq df    p
age     0.188  1 0.66
sex     2.305  1 0.13
ph.ecog 2.054  1 0.15
GLOBAL  4.464  3 0.22

Lecture de la sortie :

  • Chaque ligne est une covariable ; la dernière ligne, GLOBAL, teste l’ensemble du modèle.
  • La règle de décision est la même partout : p ≥ 0.05 → l’hypothèse PH est appuyée (aucune tendance temporelle) ; p < 0.05 → l’hypothèse PH est violée pour cette covariable.
  • Ici, chaque p-value par covariable est confortablement grande — age p = 0.66, sex p = 0.13, ph.ecog p = 0.15 — et le test GLOBAL est p = 0.22 (χ² = 4.46 à 3 df). Aucun n’est significatif, donc l’ hypothèse des risques proportionnels est appuyée pour ce modèle : les hazard ratios peuvent être lus comme constants au cours du temps.
NoteComment formuler le verdict

L’hypothèse des risques proportionnels est appuyée par une relation non significative entre les résidus de Schoenfeld mis à l’échelle et le temps, et réfutée par une relation significative. Lisez toujours le test GLOBAL (le modèle entier) conjointement avec les tests par covariable (quelle covariable est en cause).

Le diagnostic emblématique : les résidus de Schoenfeld mis à l’échelle (ggcoxzph())

Le nombre est rassurant ; c’est l’image que vous mettez dans un article. ggcoxzph() de survminer trace, pour chaque covariable, les résidus de Schoenfeld mis à l’échelle en fonction du temps transformé, avec une spline de lissage et une bande à ±2 erreurs standard. Passez-lui l’objet cox.zph que vous venez de créer :

library(survival)
library(survminer)

res.cox <- coxph(Surv(time, status) ~ age + sex + ph.ecog, data = lung)
test.ph <- cox.zph(res.cox)

ggcoxzph(test.ph)

A survminer ggcoxzph diagnostic with one panel per covariate (age, sex, ECOG score), each showing scaled Schoenfeld residuals plotted against transformed survival time. In every panel the solid smoothing spline is roughly flat and horizontal, staying within the dashed plus-or-minus two-standard-error band, indicating no systematic time trend and supporting the proportional-hazards assumption.

Comment le lire (la seule compétence qui compte ici) :

  • La ligne pleine est une spline de lissage passant par les résidus ; les lignes en pointillés sont une bande à ±2 SE.
  • Une ligne plate et horizontale (aucune tendance avec le temps) signifie que l’effet est constantl’hypothèse PH tient.
  • Une pente ou une courbe systématique — la ligne qui dérive vers le haut ou le bas au fil du suivi — signifie que le hazard ratio change au cours du tempsl’hypothèse PH est violée pour cette covariable.
  • Dans les trois panneaux, la spline est essentiellement plate et reste à l’intérieur de la bande, il n’y a donc aucun motif avec le temps : l’hypothèse est appuyée pour age, sex (le facteur à deux niveaux explique les deux bandes de résidus), et ph.ecog. Cela correspond exactement aux p-values non significatives de cox.zph().
AstuceUne seconde vérification graphique pour les covariables catégorielles

Pour un prédicteur catégoriel, vous pouvez aussi tracer log(−log(S(t))) en fonction du temps (ou du log-temps) pour chaque groupe et rechercher des courbes parallèles — des lignes parallèles appuient l’hypothèse PH, des lignes qui se croisent ou convergent signalent une violation. L’approche par résidus de Schoenfeld ci-dessus est la méthode de référence générale (elle gère aussi les covariables continues), c’est donc par elle que nous commençons.

Observations influentes (ggcoxdiagnostics())

Une seconde question pour tout modèle : l’ajustement est-il porté par quelques patients atypiques ? Deux types de résidus y répondent, tous deux via ggcoxdiagnostics() de survminer :

  • type = "dfbeta" trace le changement estimé de chaque coefficient de régression lorsque chaque observation est supprimée tour à tour — un grand dfbeta signifie que retirer ce seul patient déplacerait beaucoup le coefficient.
  • type = "deviance" trace les résidus de déviance, une transformation symétrique des résidus de martingale.

dfbeta — de combien chaque patient déplace les coefficients

library(survival)
library(survminer)

res.cox <- coxph(Surv(time, status) ~ age + sex + ph.ecog, data = lung)

ggcoxdiagnostics(res.cox, type = "dfbeta", linear.predictions = FALSE)

A survminer ggcoxdiagnostics dfbeta plot with one panel per covariate (age, sex, ECOG score), each showing the change in that coefficient when each observation is deleted, plotted against observation index. The points scatter around zero with no single observation dominating, indicating no terribly influential patients.

Lisez-le : comparez l’ampleur des plus grandes valeurs dfbeta à la taille des coefficients eux-mêmes. Ici, une poignée de points pour age et ph.ecog sont plus grands que les autres, mais aucun n’est grand par rapport à son coefficient — aucun patient n’est terriblement influent, nous n’avons donc besoin de retirer personne. Si un point éclipsait les autres, vous inspecteriez ce patient et vérifieriez si le résultat dépend de lui.

Résidus de déviance — qui est mal prédit

library(survival)
library(survminer)

res.cox <- coxph(Surv(time, status) ~ age + sex + ph.ecog, data = lung)

ggcoxdiagnostics(res.cox, type = "deviance", linear.predictions = FALSE)

A survminer ggcoxdiagnostics deviance-residual plot showing deviance residuals against observation index. The points are roughly symmetrically distributed about zero, with no extreme outliers, indicating the model predicts most patients reasonably well.

Lisez-le : les résidus de déviance devraient être à peu près symétriques autour de zéro avec un écart-type proche de 1. Les valeurs positives signalent les patients « décédés trop tôt » par rapport à la prédiction du modèle ; les valeurs négatives, ceux qui ont « vécu trop longtemps » ; les valeurs très grandes ou très petites sont des valeurs aberrantes mal prédites. Le motif ici est plutôt symétrique autour de zéro, sans points extrêmes — le modèle prédit raisonnablement bien la plupart des patients.

Non-linéarité : la forme fonctionnelle des covariables continues (ggcoxfunctional())

La régression de Cox suppose que chaque covariable continue entre linéairement sur l’échelle du log-risque — mais age pourrait agir de façon non linéaire (disons, risque plat jusqu’à 60 ans, puis croissant). La vérification standard trace les résidus de martingale d’un modèle nul en fonction de la covariable et examine l’ajustement lowess (lissé) : il devrait être à peu près linéaire. ggcoxfunctional() de survminer fait cela ; ajustez un petit modèle de Cox qui inclut la covariable sous plusieurs formes — age, log(age), sqrt(age) — et passez-le :

library(survival)
library(survminer)

cox.age <- coxph(Surv(time, status) ~ age + log(age) + sqrt(age), data = lung)

ggcoxfunctional(cox.age, data = lung)

A survminer ggcoxfunctional plot with three panels showing martingale residuals against age, log(age), and sqrt(age) from a null Cox model on the lung data, each with a lowess smoothing line. The smooths are close to linear with only a slight bend, indicating age can reasonably enter the model in linear form.

Lisez-le : une ligne lowess droite signifie que la covariable est bien ajustée sous cette forme ; une nette courbure signifie que vous devriez la transformer (utilisez log(age), une spline ou des termes polynomiaux) plutôt que age brut. La non-linéarité n’est pertinente que pour les covariables continues — ce n’est pas un problème pour les covariables catégorielles comme sex. Ici, les lissages sont proches de la linéarité avec seulement une légère courbure, entrer age linéairement est donc raisonnable.

Que faire quand les risques proportionnels échouent

Quand cox.zph() signale une covariable (p < 0.05) ou que son panneau ggcoxzph() montre une tendance nette, vous ne jetez pas le modèle — vous tenez compte de l’effet dépendant du temps. Les principaux remèdes :

  • Stratifier la covariable fautivecoxph(Surv(time, status) ~ age + sex + strata(ph.ecog)) laisse chaque strate avoir son propre risque de base, de sorte que l’hypothèse PH n’a plus besoin de tenir pour cette variable. Idéal pour un facteur de confusion « nuisance » dont vous n’avez pas besoin d’une estimation d’effet (vous perdez son hazard ratio).
  • Ajouter un coefficient dépendant du temps — modélisez l’effet comme une fonction du temps, par ex. avec tt() : coxph(Surv(time, status) ~ sex + tt(sex), tt = function(x, t, ...) x * log(t)), ou scindez le suivi à un point de coupure et ajustez un HR distinct par intervalle (un effet précoce vs tardif).
  • Ajouter une interaction covariable × temps — une version en fonction par paliers de ce qui précède, donnant un résultat interprétable « l’effet pendant les 12 premiers mois vs après ».
  • Utiliser un test log-rank pondéré (Fleming-Harrington) pour la comparaison de groupes quand les courbes se croisent — il surpondère les différences précoces ou tardives au lieu de supposer un rapport constant.
AstuceChoisir le remède selon ce qui est violé
  • Une covariable catégorielle « nuisance » viole l’hypothèse PH → stratifiez-la.
  • Un traitement / effet clé change au cours du temps → un coefficient dépendant du temps ou une interaction avec le temps (pour que vous puissiez rapporter l’effet précoce vs tardif).
  • Les courbes de survie des groupes se croisent → envisagez un test log-rank pondéré aux côtés du modèle de Cox.

Rapport

L’hypothèse des risques proportionnels du modèle de Cox multivarié (âge, sexe, score ECOG) a été évaluée avec les résidus de Schoenfeld mis à l’échelle (cox.zph). Il n’y avait aucune preuve de violation pour aucune covariable (âge p = 0.66, sexe p = 0.13, score ECOG p = 0.15) ni pour le modèle dans son ensemble (GLOBAL χ²(3) = 4.46, p = 0.22) ; les graphiques de résidus ggcoxzph n’ont montré aucune tendance systématique avec le temps. Les diagnostics d’influence (dfbeta, résidus de déviance) n’ont révélé aucune observation indûment influente, et les résidus de martingale appuyaient une forme fonctionnelle linéaire pour l’âge. L’hypothèse des risques proportionnels a donc été considérée comme satisfaite.

À chaque temps d’événement, le résidu de Schoenfeld d’une covariable est la différence entre la valeur de la covariable du patient ayant connu l’événement et la valeur attendue sur l’ensemble des patients encore à risque :

\[ r_{ij} = x_{ij} - \bar{x}_{j}(t_i) \]

\(x_{ij}\) est la covariable \(j\) pour le patient ayant un événement au temps \(t_i\), et \(\bar{x}_{j}(t_i)\) est la moyenne de cette covariable pondérée par l’ensemble à risque à \(t_i\). Il y a un résidu par événement (aucun pour les observations censurées), par covariable.

Grambsch et Therneau ont montré que les résidus de Schoenfeld mis à l’échelle ont une valeur attendue qui est approximativement le coefficient dépendant du temps \(\beta_j(t)\). Donc, sous risques proportionnels, \(\beta_j(t) = \beta_j\) est constant, et un graphique des résidus mis à l’échelle en fonction du temps devrait être plat. cox.zph() formalise cela en testant si les résidus sont corrélés avec le temps (une pente non nulle \(\Rightarrow\) un effet dépendant du temps \(\Rightarrow\) hypothèse PH violée). C’est exactement la règle « ligne plate = bon » que vous relevez sur ggcoxzph().

Quel diagnostic, quand ?

AstuceChoisir votre diagnostic de Cox
  • Les hazard ratios sont-ils constants au cours du temps ?cox.zph() + ggcoxzph() (résidus de Schoenfeld mis à l’échelle) — le test PH, l’événement principal.
  • Est-ce qu’une poignée de patients porte l’ajustement ?ggcoxdiagnostics(fit, type = "dfbeta") (influence sur les coefficients) et type = "deviance" (valeurs aberrantes mal prédites).
  • Une covariable continue entre-t-elle linéairement ?ggcoxfunctional() (résidus de martingale).
  • L’hypothèse PH est violée — et maintenant ? → stratifier, coefficient dépendant du temps (tt()), interaction avec le temps, ou un test log-rank pondéré.

Essayez en direct

Testez vous-même l’hypothèse — exécutez cox.zph() et tracez les panneaux ggcoxzph(). Essayez d’ajouter wt.loss au modèle, ou vérifiez une seule covariable. Le bac à sable démarre au premier Run.

🟢 Avec un agent IA

Demandez à Prova « teste l’hypothèse des risques proportionnels de mon modèle de Cox avec cox.zph et ggcoxzph, dis-moi en mots simples si elle tient, et si elle est violée montre-moi comment la corriger » — 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

Vous ne lisez que le test GLOBAL, ou seulement les tests par covariable. Lisez les deux. Un test GLOBAL non significatif avec une covariable significative signifie tout de même que cette covariable viole l’hypothèse PH et demande votre attention ; un GLOBAL significatif avec toutes les covariables à la limite vous dit que quelque chose cloche mais pas où. Le test GLOBAL répond à « le modèle est-il correct dans l’ensemble ? », les lignes par covariable répondent à « quelle variable est le problème ? ».

Un test PH « significatif » sur un très grand échantillon n’est pas toujours un vrai problème. Avec des milliers d’événements, cox.zph() peut signaler une minuscule tendance temporelle cliniquement non pertinente comme statistiquement significative. Regardez toujours le graphique ggcoxzph() : une ligne de résidus essentiellement plate mais techniquement inclinée est bien moins préoccupante qu’une qui dérive ou s’inverse nettement. Jugez la magnitude et la forme, pas seulement la p-value.

Un petit échantillon rend le test bruyant. Avec peu d’événements, les résidus de Schoenfeld mis à l’échelle sont bruyants et le test a une faible puissance — un résultat non significatif est une preuve faible que l’hypothèse PH tient, et une large bande de confiance sur le graphique est attendue. Associez le test au graphique et à un raisonnement clinique sur la question de savoir si l’effet devrait changer au cours du temps.

ggcoxfunctional() génère une erreur sur la forme de formule. Les versions récentes de survminer veulent le modèle ajusté, et non une formule : ajustez d’abord cox.age <- coxph(Surv(time, status) ~ age + log(age) + sqrt(age), data = lung), puis appelez ggcoxfunctional(cox.age, data = lung).

Questions fréquentes

Ajustez votre modèle de Cox avec coxph(), puis passez-le à cox.zph() : test.ph <- cox.zph(res.cox). Il renvoie un test par covariable plus un test GLOBAL, chacun fondé sur les résidus de Schoenfeld mis à l’échelle. Une p-value non significative (≥ 0.05) appuie les risques proportionnels ; une p-value significative (< 0.05) signifie qu’ils sont violés. Visualisez-le avec ggcoxzph(test.ph) de survminer.

Une p-value cox.zph() significative (< 0.05) signifie que le hazard ratio de cette covariable n’est pas constant au cours du temps — l’hypothèse des risques proportionnels est violée, donc le HR unique que le modèle de Cox rapporte est une moyenne temporelle trompeuse. Regardez le panneau ggcoxzph() pour voir la forme de la tendance temporelle, puis corrigez-la en stratifiant la covariable, en ajoutant un coefficient dépendant du temps (tt()) ou une interaction avec le temps, ou en utilisant un test log-rank pondéré.

Les résidus de Schoenfeld sont, à chaque temps d’événement, la différence entre la valeur de la covariable du patient ayant connu l’événement et la valeur moyenne de la covariable parmi tous ceux encore à risque — un résidu par événement, par covariable. Les résidus de Schoenfeld mis à l’échelle suivent le coefficient dépendant du temps β(t), donc sous risques proportionnels un graphique de ceux-ci en fonction du temps devrait être plat. Une tendance systématique signifie que l’effet change au cours du temps, c’est-à-dire que l’hypothèse PH est violée. C’est exactement ce que cox.zph() teste et que ggcoxzph() trace.

Utilisez ggcoxdiagnostics() de survminer. type = "dfbeta" montre de combien chaque coefficient changerait si chaque observation était supprimée — une valeur grande par rapport au coefficient signale un patient influent. type = "deviance" montre les résidus de déviance, qui devraient être à peu près symétriques autour de zéro ; les valeurs très grandes ou très petites sont des valeurs aberrantes mal prédites qui méritent une inspection.

Tracez les résidus de martingale en fonction de la covariable avec ggcoxfunctional() et examinez le lissage lowess : à peu près droit signifie qu’une forme linéaire convient ; une nette courbure signifie que vous devriez transformer la covariable (par ex. log(), une spline ou des termes polynomiaux). Cela n’importe que pour les covariables continues — les covariables catégorielles ne peuvent pas être non linéaires.

Testez vos connaissances

  1. Exécutez-le. Dans la cellule interactive ci-dessous, ajustez un modèle de Cox qui ajoute wt.loss (perte de poids) au modèle, puis testez les risques proportionnels avec cox.zph(). Remplissez le blanc. Est-ce que wt.loss satisfait l’hypothèse PH, et le test GLOBAL ?
  2. Interprétez. Un test GLOBAL cox.zph() donne p = 0.004, avec treatment p = 0.002 et toutes les autres covariables p > 0.3. Quelle hypothèse est violée, pour quelle covariable, et nommez un remède approprié.

Remplissez le blanc avec wt.loss. Lisez la p-value de chaque ligne : p ≥ 0.05 signifie que l’hypothèse PH est appuyée pour cette covariable ; vérifiez la ligne GLOBAL pour l’ensemble du modèle. Les panneaux ggcoxzph() devraient être plats si l’hypothèse PH tient.

res.cox <- coxph(Surv(time, status) ~ age + sex + ph.ecog + wt.loss, data = lung)
test.ph <- cox.zph(res.cox)
test.ph
#> Every per-covariate p-value and the GLOBAL p-value are > 0.05 (non-significant),
#> so the proportional-hazards assumption is SUPPORTED for the model — including wt.loss.
#> The ggcoxzph() panels show flat smoothing lines, confirming no time trend.

Pour la question 2 : l’hypothèse des risques proportionnels est violée (GLOBAL p = 0.004 < 0.05), et le coupable est treatment (p = 0.002), puisque les autres covariables sont non significatives. L’effet du traitement change au cours du temps. Un remède approprié : le modéliser avec un coefficient dépendant du temps (tt()) ou une interaction traitement × temps pour que vous puissiez rapporter l’effet précoce vs tardif (stratifier treatment masquerait l’effet même qui vous intéresse). Un test log-rank pondéré est un complément raisonnable pour la comparaison de groupes.

AstuceVérification rapide

cox.zph() renvoie une p-value GLOBAL de 0.45, et chaque p-value par covariable est supérieure à 0.3. Que concluez-vous ?

L’hypothèse des risques proportionnels est appuyée. Toutes les p-values sont non significatives (≥ 0.05), il n’y a donc aucune preuve que le hazard ratio d’une covariable change au cours du temps — les hazard ratios du modèle de Cox peuvent être lus comme constants sur le suivi, et aucun remède (stratification, coefficient dépendant du temps) n’est nécessaire. Confirmez avec le graphique ggcoxzph() : les lignes de lissage devraient être plates.

Conclusion

Vous savez désormais valider un modèle de Cox à risques proportionnels en R. Testez l’hypothèse centrale avec cox.zph() — en lisant les tests par covariable et GLOBAL, où une p-value non significative appuie l’hypothèse PH — et visualisez-la avec le graphique des résidus de Schoenfeld mis à l’échelle ggcoxzph() de survminer, où une ligne plate signifie que les hazard ratios tiennent dans le temps. Complétez la vérification avec ggcoxdiagnostics() pour les observations influentes (dfbeta, déviance) et ggcoxfunctional() pour la forme fonctionnelle des covariables continues. Sur le modèle du cancer du poumon, chaque diagnostic a réussi (GLOBAL p = 0.22), donc les hazard ratios de la leçon sur Cox sont fiables. Et quand un diagnostic échoue, vous connaissez désormais les correctifs — stratifier, un coefficient dépendant du temps, une interaction avec le temps ou un test log-rank pondéré — de sorte qu’une violation est un problème que vous résolvez, et non un résultat que vous écartez.

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 = {Tester l’hypothèse des risques proportionnels en R (cox.zph,
    Schoenfeld)},
  date = {2026-06-25},
  url = {https://www.datanovia.com/learn/biostatistics/survival-analysis/testing-ph-assumptions},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Tester l’hypothèse des risques proportionnels en R (cox.zph, Schoenfeld).” 2026. June 25. https://www.datanovia.com/learn/biostatistics/survival-analysis/testing-ph-assumptions.