When testing the Proportionnal Hazard assumption in a cox model in R, you usually use the survival::cox.zph() function.

Output is something like this:

my.cox.model = coxph(someFormula)
#               rho    chisq      p
# x1:A     -0.01166   0.4931  0.483
# x1:B     -0.01135   0.4655  0.495
# x1:C      0.00799   0.2328  0.629
# x2        0.02412   2.0777  0.149
# x3        0.00239   0.0204  0.886
# x4        0.00463   0.0767  0.001 **
# GLOBAL         NA  37.5889  0.308

But in doing so, I've made 7 tests in a row, so my alpha (I use 5%) may be broken and I could think there is a HP problem for x4 because of sole randomness.

Would it make sense to adjust these p-values for multiple comparisons ?

If yes, would a Bonferroni correction be OK ? And should I account the last line ("Global" test) as a hypothesis test ?

PS: The help ?cox.zph does not say anything about any correction.


You don't want to do multiple-comparison corrections for cox.zph() types of tests, as you are trying to protect yourself from something different than Type I errors.

When you are trying to disprove a null hypothesis, you want to convince a skeptical reviewer that your results are not simply false positives due to chance. Multiple-comparison correction is an important part of that effort to minimize Type I errors.

For testing the proportional hazards (PH) assumption, you want to convince a skeptical reviewer that a Cox model with its assumption of PH is a valid approach. In effect you would like to prove the null hypothesis of the cox.zph() test that PH holds. That isn't formally possible, so you need to be sensitive to any indications that PH is violated and take appropriate action in that case. Put another way, you want to err on the side of potential false-positives for violation of PH. Thus multiple-comparison corrections go in the wrong direction.

I at least start to worry if I find p-values below 0.2 or 0.1 in cox.zph(), as those values mean that there is only a 20% or 10% chance that such a deviation from true PH is due to chance. I immediately take action if I see "significant" p-values like yours for x4. You should certainly look at the plots of scaled Schoenfeld residuals over time that cox.zph() provides, to get a sense of what might be going on. Stratification on the variable(s) potentially violating PH can help.

  • $\begingroup$ The way you describe it make it look like cox.zph is not really a test, but more like a statictic like concordance, which you compare to 0.5 or 0.7. Why making it a test then ? And how can the p-value not be <0.05 "by chance" in 5% of cases, like a false positive broken PH assumption ? $\endgroup$ – Dan Chaltiel Sep 5 '18 at 17:19
  • $\begingroup$ @DanChaltiel cox.zph() is a test, but it should not be used as a "significance test" of a slope=0 null hypothesis of PH in the way that one normally uses t-tests, etc. You have to try to convince a skeptical reviewer that the PH assumption is actually met, not that you can't rule out a PH assumption except when p<0.05. Put another way, you need to guard more against Type II than against Type I error here. Yes, if you do enough cox.zph() tests in cases where PH holds you should get a uniform distribution of p-values. But with p<0.001 I'd worry and examine stratification as an alternative. $\endgroup$ – EdM Sep 5 '18 at 19:34
  • $\begingroup$ @DanChaltiel, @EdM, AFAIK the test performed by cox.zph() is a test for the correlation coefficient between the Schoenfeld residuals and time (or a transformation of time, if this was indicated when calling the function). Tests for correlation coefficients are known to be significant even when the correlation is very mild (e.g., 0.1, 0.2), if the sample size is moderately large. Therefore, the advice I personally give is to better check the plot of the Scoenfeld residuals versus time. This is almost always more informative than doing the test. $\endgroup$ – Dimitris Rizopoulos Sep 7 '18 at 14:03
  • $\begingroup$ @DimitrisRizopoulos @EdM I think I get the point, thanks. My plots are highly reassuring, regardless of the transform argument I use in cox.zph(). This latter is kind of unclear BTW. When should I use one or the other ? $\endgroup$ – Dan Chaltiel Sep 17 '18 at 13:52
  • $\begingroup$ @DanChaltiel I use the default km time transformation as it presumably is the favorite of the highly experienced package authors and spreads out the cases along the time axis reasonably well, usefully incorporating information about the survival characteristics of the cohort. Untransformed time (identity) makes it hard to see what's going on at early times if there are late events. Ordering by rank effectively throws away much time information. As the issue is to try to identify potential violations of PH, use whatever time transformation is useful for display with that issue in mind. $\endgroup$ – EdM Sep 17 '18 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.