当风险数量<1时,如何截断Kaplan Meier曲线10

时间:2018-01-16 20:57:30

标签: r survival-analysis

对于在同行评审的科学期刊(http://www.redjournal.org)中的出版物,我们希望准备Kaplan-Meier图。该期刊对这些图有以下具体指导原则:

&#34;如果您的数据包括使用Kaplan-Meier方法或累积入射方法分析生成的曲线,则以下是现在要求显示这些曲线:

  1. 指出有风险的患者人数;
  2. 包括审查标记;
  3. 当少于10名患者处于危险中时,该曲线会被截断;和
  4. 置信区间的估计值应包括在图中本身或文本中。“
  5. 在这里,我用经验丰富的数据集来说明我的问题(https://github.com/tidyverse/reprex很棒!)。 我们可以使用survminer包轻松地分辨1,2和4:

    library(survival)
    library(survminer)
    #> Warning: package 'survminer' was built under R version 3.4.3
    #> Loading required package: ggplot2
    #> Loading required package: ggpubr
    #> Warning: package 'ggpubr' was built under R version 3.4.3
    #> Loading required package: magrittr
    
    fit.obj <- survfit(Surv(time, status) ~ celltype, data = veteran)
    
    ggsurvplot(fit.obj,
               conf.int = T,
               risk.table ="absolute",
               tables.theme = theme_cleantable())
    

    然而,我有一个问题3的问题(当有少于10名患者处于危险中时截断曲线)。我看到所有必需的信息都可以在survfit对象中找到:

    library(survival)
    fit.obj <- survfit(Surv(time, status) ~ celltype, data = veteran)
    summary(fit.obj)
    #> Call: survfit(formula = Surv(time, status) ~ celltype, data = veteran)
    #> 
    #>                 celltype=squamous 
    #>  time n.risk n.event survival std.err lower 95% CI upper 95% CI
    #>     1     35       2    0.943  0.0392       0.8690        1.000
    #>     8     33       1    0.914  0.0473       0.8261        1.000
    #>    10     32       1    0.886  0.0538       0.7863        0.998
    #>    11     31       1    0.857  0.0591       0.7487        0.981
    #>    15     30       1    0.829  0.0637       0.7127        0.963
    #>    25     29       1    0.800  0.0676       0.6779        0.944
    #>    30     27       1    0.770  0.0713       0.6426        0.924
    #>    33     26       1    0.741  0.0745       0.6083        0.902
    #>    42     25       1    0.711  0.0772       0.5749        0.880
    #>    44     24       1    0.681  0.0794       0.5423        0.856
    #>    72     23       1    0.652  0.0813       0.5105        0.832
    #>    82     22       1    0.622  0.0828       0.4793        0.808
    #>   110     19       1    0.589  0.0847       0.4448        0.781
    #>   111     18       1    0.557  0.0861       0.4112        0.754
    #>   112     17       1    0.524  0.0870       0.3784        0.726
    #>   118     16       1    0.491  0.0875       0.3464        0.697
    #>   126     15       1    0.458  0.0876       0.3152        0.667
    #>   144     14       1    0.426  0.0873       0.2849        0.636
    #>   201     13       1    0.393  0.0865       0.2553        0.605
    #>   228     12       1    0.360  0.0852       0.2265        0.573
    #>   242     10       1    0.324  0.0840       0.1951        0.539
    #>   283      9       1    0.288  0.0820       0.1650        0.503
    #>   314      8       1    0.252  0.0793       0.1362        0.467
    #>   357      7       1    0.216  0.0757       0.1088        0.429
    #>   389      6       1    0.180  0.0711       0.0831        0.391
    #>   411      5       1    0.144  0.0654       0.0592        0.351
    #>   467      4       1    0.108  0.0581       0.0377        0.310
    #>   587      3       1    0.072  0.0487       0.0192        0.271
    #>   991      2       1    0.036  0.0352       0.0053        0.245
    #>   999      1       1    0.000     NaN           NA           NA
    #> 
    #>                 celltype=smallcell 
    #>  time n.risk n.event survival std.err lower 95% CI upper 95% CI
    #>     2     48       1   0.9792  0.0206      0.93958        1.000
    #>     4     47       1   0.9583  0.0288      0.90344        1.000
    #>     7     46       2   0.9167  0.0399      0.84172        0.998
    #>     8     44       1   0.8958  0.0441      0.81345        0.987
    #>    10     43       1   0.8750  0.0477      0.78627        0.974
    #>    13     42       2   0.8333  0.0538      0.73430        0.946
    #>    16     40       1   0.8125  0.0563      0.70926        0.931
    #>    18     39       2   0.7708  0.0607      0.66065        0.899
    #>    20     37       2   0.7292  0.0641      0.61369        0.866
    #>    21     35       2   0.6875  0.0669      0.56812        0.832
    #>    22     33       1   0.6667  0.0680      0.54580        0.814
    #>    24     32       1   0.6458  0.0690      0.52377        0.796
    #>    25     31       2   0.6042  0.0706      0.48052        0.760
    #>    27     29       1   0.5833  0.0712      0.45928        0.741
    #>    29     28       1   0.5625  0.0716      0.43830        0.722
    #>    30     27       1   0.5417  0.0719      0.41756        0.703
    #>    31     26       1   0.5208  0.0721      0.39706        0.683
    #>    51     25       2   0.4792  0.0721      0.35678        0.644
    #>    52     23       1   0.4583  0.0719      0.33699        0.623
    #>    54     22       2   0.4167  0.0712      0.29814        0.582
    #>    56     20       1   0.3958  0.0706      0.27908        0.561
    #>    59     19       1   0.3750  0.0699      0.26027        0.540
    #>    61     18       1   0.3542  0.0690      0.24171        0.519
    #>    63     17       1   0.3333  0.0680      0.22342        0.497
    #>    80     16       1   0.3125  0.0669      0.20541        0.475
    #>    87     15       1   0.2917  0.0656      0.18768        0.453
    #>    95     14       1   0.2708  0.0641      0.17026        0.431
    #>    99     12       2   0.2257  0.0609      0.13302        0.383
    #>   117      9       1   0.2006  0.0591      0.11267        0.357
    #>   122      8       1   0.1755  0.0567      0.09316        0.331
    #>   139      6       1   0.1463  0.0543      0.07066        0.303
    #>   151      5       1   0.1170  0.0507      0.05005        0.274
    #>   153      4       1   0.0878  0.0457      0.03163        0.244
    #>   287      3       1   0.0585  0.0387      0.01600        0.214
    #>   384      2       1   0.0293  0.0283      0.00438        0.195
    #>   392      1       1   0.0000     NaN           NA           NA
    #> 
    #>                 celltype=adeno 
    #>  time n.risk n.event survival std.err lower 95% CI upper 95% CI
    #>     3     27       1   0.9630  0.0363      0.89430        1.000
    #>     7     26       1   0.9259  0.0504      0.83223        1.000
    #>     8     25       2   0.8519  0.0684      0.72786        0.997
    #>    12     23       1   0.8148  0.0748      0.68071        0.975
    #>    18     22       1   0.7778  0.0800      0.63576        0.952
    #>    19     21       1   0.7407  0.0843      0.59259        0.926
    #>    24     20       1   0.7037  0.0879      0.55093        0.899
    #>    31     19       1   0.6667  0.0907      0.51059        0.870
    #>    35     18       1   0.6296  0.0929      0.47146        0.841
    #>    36     17       1   0.5926  0.0946      0.43344        0.810
    #>    45     16       1   0.5556  0.0956      0.39647        0.778
    #>    48     15       1   0.5185  0.0962      0.36050        0.746
    #>    51     14       1   0.4815  0.0962      0.32552        0.712
    #>    52     13       1   0.4444  0.0956      0.29152        0.678
    #>    73     12       1   0.4074  0.0946      0.25850        0.642
    #>    80     11       1   0.3704  0.0929      0.22649        0.606
    #>    84      9       1   0.3292  0.0913      0.19121        0.567
    #>    90      8       1   0.2881  0.0887      0.15759        0.527
    #>    92      7       1   0.2469  0.0850      0.12575        0.485
    #>    95      6       1   0.2058  0.0802      0.09587        0.442
    #>   117      5       1   0.1646  0.0740      0.06824        0.397
    #>   132      4       1   0.1235  0.0659      0.04335        0.352
    #>   140      3       1   0.0823  0.0553      0.02204        0.307
    #>   162      2       1   0.0412  0.0401      0.00608        0.279
    #>   186      1       1   0.0000     NaN           NA           NA
    #> 
    #>                 celltype=large 
    #>  time n.risk n.event survival std.err lower 95% CI upper 95% CI
    #>    12     27       1   0.9630  0.0363      0.89430        1.000
    #>    15     26       1   0.9259  0.0504      0.83223        1.000
    #>    19     25       1   0.8889  0.0605      0.77791        1.000
    #>    43     24       1   0.8519  0.0684      0.72786        0.997
    #>    49     23       1   0.8148  0.0748      0.68071        0.975
    #>    52     22       1   0.7778  0.0800      0.63576        0.952
    #>    53     21       1   0.7407  0.0843      0.59259        0.926
    #>   100     20       1   0.7037  0.0879      0.55093        0.899
    #>   103     19       1   0.6667  0.0907      0.51059        0.870
    #>   105     18       1   0.6296  0.0929      0.47146        0.841
    #>   111     17       1   0.5926  0.0946      0.43344        0.810
    #>   133     16       1   0.5556  0.0956      0.39647        0.778
    #>   143     15       1   0.5185  0.0962      0.36050        0.746
    #>   156     14       1   0.4815  0.0962      0.32552        0.712
    #>   162     13       1   0.4444  0.0956      0.29152        0.678
    #>   164     12       1   0.4074  0.0946      0.25850        0.642
    #>   177     11       1   0.3704  0.0929      0.22649        0.606
    #>   200      9       1   0.3292  0.0913      0.19121        0.567
    #>   216      8       1   0.2881  0.0887      0.15759        0.527
    #>   231      7       1   0.2469  0.0850      0.12575        0.485
    #>   250      6       1   0.2058  0.0802      0.09587        0.442
    #>   260      5       1   0.1646  0.0740      0.06824        0.397
    #>   278      4       1   0.1235  0.0659      0.04335        0.352
    #>   340      3       1   0.0823  0.0553      0.02204        0.307
    #>   378      2       1   0.0412  0.0401      0.00608        0.279
    #>   553      1       1   0.0000     NaN           NA           NA
    

    但我不知道如何操纵这个清单。我非常感谢有关如何使用n.risk&lt;过滤掉所有行的任何建议。 10来自fit.obj。

3 个答案:

答案 0 :(得分:3)

我似乎无法将其全部带到那里。但我发现你可以将data.frame而不是fit对象传递给绘图函数。您可以执行此操作并剪切值。例如

ss <- subset(surv_summary(fit.obj), n.risk>=10)
ggsurvplot(ss,
      conf.int = T)

但似乎在这种模式下它不会自动打印表格。有一个函数只用

绘制表格
ggrisktable(fit.obj, tables.theme = theme_cleantable())

所以我想你可以把它们结合起来。也许在同一个图中使用data.frame时,我错过了一种更简单的方法来绘制表格。

答案 1 :(得分:3)

与上述答案略有不同,如果您要在每个组中有少于10名患者处于危险之中时分别截断每个组,我发现这是行得通的,不需要分别绘制图形和表格:

library(survival)
library(survminer)

# truncate each line when fewer than 10 at risk
atrisk <- 10

# KM fit
fit.obj <- survfit(Surv(time, status) ~ celltype, data = veteran)

# subset each stratum separately
maxcutofftime = 0 # for plotting
strata <- rep(names(fit.obj$strata), fit.obj$strata)
for (i in names(fit.obj$strata)){
    cutofftime <- min(fit.obj$time[fit.obj$n.risk < atrisk & strata == i])
    maxcutofftime = max(maxcutofftime, cutofftime)
    cutoffs <- which(fit.obj$n.risk < atrisk & strata == i)
    fit.obj$lower[cutoffs] <- NA
    fit.obj$upper[cutoffs] <- NA
    fit.obj$surv[cutoffs] <- NA
}


# plot
ggsurvplot(fit.obj, data = veteran, risk.table = TRUE, conf.int = T, pval = F, 
           tables.theme = theme_cleantable(), xlim = c(0,maxcutofftime), break.x.by = 90)


KM plot with each group truncated separately

编辑后添加:请注意,如果我们使用上面的pval = T,它将为截断后的数据而不是完整数据提供p值。在此示例中,两者的差异均不大,因为它们均为p <0.0001,但请注意:)

答案 2 :(得分:1)

我正在跟进MrFlick的好回答。

  1. 我认为3)意味着总共应该有至少10个风险 - 即不是每组。因此,我们必须首先创建一个未组合的Kaplan-Meier拟合,然后确定从那里截止的时间。
  2. surv_summary对象w / r / t设置为此截止值。
  3. 分别绘制KM曲线和风险表。至关重要的是,功能survminer::ggrisktable()ggsurvtable()的最小前端)接受选项xlimbreak.time.by。但是,该功能目前只能延长上限时间,而不是减少它。我认为这是一个错误。我创建了函数ggsurvtable_mod()来改变它。
  4. ggplot个对象转换为grob,然后使用ggExtra::grid.arrange()将两个图块放在一起。根据选项widthsheights
  5. ,可能有更优雅的方法

    不可否认,这是一个黑客攻击,需要调整以获得生存图和风险表之间的正确对齐。

    library(survival)
    library(survminer)
    
    # ungrouped KM estimate to determine cutoff
    fit1_ss <- surv_summary(survfit(Surv(time, status) ~ 1, data=veteran))
    
    # time cutoff with fewer than 10 at risk
    cutoff  <- min(fit1_ss$time[fit1_ss$n.risk < 10])
    
    # KM fit and subset to cutoff
    fit.obj <- survfit(Surv(time, status) ~ celltype, data = veteran)
    fit_ss  <- subset(surv_summary(fit.obj), time < cutoff)
    
    # KM survival plot and risk table as separate plots
    p1 <- ggsurvplot(fit_ss, conf.int=TRUE)
    # note options xlim and break.time.by
    p2 <- ggsurvtable_mod(fit.obj,
                          survtable="risk.table",
                          tables.theme=theme_cleantable(),
                          xlim=c(0, cutoff),
                          break.time.by=100)
    
    # turn ggplot objects into grobs and arrange them (needs tweaking)
    g1  <- ggplotGrob(p1)
    g2  <- ggplotGrob(p2)
    lom <- rbind(c(NA, rep(1, 14)),
                 c(NA, rep(1, 14)),
                 c(rep(2, 15)))
    
    gridExtra::grid.arrange(grobs=list(g1, g2), layout_matrix=lom)
    

    enter image description here