Análise de sobrevida

Autor

Marcelo Silva

Carregando pacotes

Código
library(tidyverse)    # For data manipulation (dplyr, readr, etc.)
library(survival)     # Core survival analysis functions (Surv, coxph)
library(survminer)    # For plotting survival curves (ggsurvplot)
library(broom)        # For tidying model outputs into tables
Código
ds_raw <- readxl::read_xlsx('SobrevidaBancoDados.xlsx')
ds <- ds_raw %>%
  select(-c(1,2)) %>% 
  janitor::clean_names() %>%
  glimpse()
Rows: 62
Columns: 19
$ localizacao      <chr> "membros", "Abdomem", "tronco", "cabeça e pescoço", "…
$ castracao        <dbl> 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0,…
$ tamanho          <dbl> 5.0, NA, NA, NA, 2.5, 5.0, 7.0, 1.5, 5.0, 3.3, 3.0, 2…
$ tamanhotumor     <chr> "grande (> 3cm)", NA, NA, NA, "pequeno (< 3cm)", "gra…
$ porte            <chr> "Grande", "Médio", "Médio", "Grande", "Pequeno", "Gra…
$ temraca          <chr> "SRD", "SRD", "SRD", "CRD", "CRD", "SRD", "CRD", "SRD…
$ raca             <chr> "SRD", "SRD", "SRD", "Outras Raças", "Yorkshire Terri…
$ sexo             <chr> "Fêmea", "Macho", "Macho", "Fêmea", "Fêmea", "Fêmea",…
$ alimentacao      <chr> "Apenas Ração", "Mista (Ração + Comida ou petiscos)",…
$ escorecorporal   <chr> "Peso ideal", NA, "Abaixo do peso ideal", "Acima do p…
$ quimioterapia    <chr> "Não", "Sim", "Sim", "Sim", "Sim", "Sim", "Sim", "Não…
$ grau_histologico <chr> "baixo grau", NA, NA, NA, "alto grau", "alto grau", "…
$ metastase        <chr> "Não", "Não", "Sim", "Não", "Não", "Sim", "Não", "Não…
$ raca_2           <chr> "SRD", "SRD", "SRD", "Outras Raças", "Yorkshire Terri…
$ margens_livres   <chr> "Não", NA, NA, NA, NA, "Não", "Sim", NA, "Não", "Não"…
$ status           <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,…
$ data_inicial     <dttm> 2017-07-04, 2017-07-14, 2017-05-17, 2018-09-06, 2019…
$ data_final       <dttm> 2017-07-17, 2017-10-23, 2017-06-30, 2018-10-28, 2019…
$ tempo            <dbl> 13, 101, 44, 52, 105, 259, 123, 212, 449, 591, 412, 6…

Missing values

Código
naniar::miss_var_summary(ds)

Criação a variável escorecorporal_binario

Código
ds <- ds %>%
  mutate(
    escorecorporal_binario = fct_collapse(
      escorecorporal,
      'Excesso de Peso' = c('Acima do peso ideal', 'Obesidade'),
      'Peso Não Excedente' = c('Abaixo do peso ideal', 'Peso ideal')
    ),
    fct_relevel(escorecorporal_binario,'Peso Não Excedente')
  )

Descrição geral dos dados

Código
DescTools::Desc(ds)
────────────────────────────────────────────────────────────────────────────── 
Describe ds (tbl_df, tbl, data.frame):

data frame: 62 obs. of  21 variables
        41 complete cases (66.1%)

  Nr  Class  ColName                                                  
  1   chr    localizacao                                              
  2   num    castracao                                                
  3   num    tamanho                                                  
  4   chr    tamanhotumor                                             
  5   chr    porte                                                    
  6   chr    temraca                                                  
  7   chr    raca                                                     
  8   chr    sexo                                                     
  9   chr    alimentacao                                              
  10  chr    escorecorporal                                           
  11  chr    quimioterapia                                            
  12  chr    grau_histologico                                         
  13  chr    metastase                                                
  14  chr    raca_2                                                   
  15  chr    margens_livres                                           
  16  num    status                                                   
  17  pos    data_inicial                                             
  18  pos    data_final                                               
  19  num    tempo                                                    
  20  fac    escorecorporal_binario                                   
                                                                      
                                                                      
                                                                      
                                                                      
                                                                      
                                                                      
  21  fac    fct_relevel(escorecorporal_binario, "Peso Não Excedente")
                                                                      
                                                                      
                                                                      
                                                                      
                                                                      
                                                                      
  NAs         Levels
   1 (1.6%)   ...   
   .          ...   
   5 (8.1%)   ...   
   5 (8.1%)   ...   
   .          ...   
   .          ...   
   .          ...   
   .          ...   
   .          ...   
   1 (1.6%)   ...   
   .          ...   
   9 (14.5%)  ...   
   .          ...   
   .          ...   
  20 (32.3%)  ...   
   .          ...   
   .          ...   
   .          ...   
   .          ...   
   1 (1.6%)   ...   
              ...   
              ...   
              ...   
              ...   
              ...   
              ...   
   1 (1.6%)   ...   
              ...   
              ...   
              ...   
              ...   
              ...   
              ...   


────────────────────────────────────────────────────────────────────────────── 
1 - localizacao (character)

  length      n    NAs unique levels  dupes
      62     61      1      5      5      y
          98.4%   1.6%                     

                               level  freq   perc  cumfreq  cumperc
1                             tronco    17  27.9%       17    27.9%
2                            membros    15  24.6%       32    52.5%
3  Perineo e regioes inguinogenitais    12  19.7%       44    72.1%
4                   cabeça e pescoço     9  14.8%       53    86.9%
5                            Abdomem     8  13.1%       61   100.0%

────────────────────────────────────────────────────────────────────────────── 
2 - castracao (numeric)

  length       n    NAs  unique     0s  mean  meanCI'
      62      62      0       2     31  0.50    0.37
          100.0%   0.0%          50.0%          0.63
                                                    
     .05     .10    .25  median    .75   .90     .95
    0.00    0.00   0.00    0.50   1.00  1.00    1.00
                                                    
   range      sd  vcoef     mad    IQR  skew    kurt
    1.00    0.50   1.01    0.74   1.00  0.00   -2.03
                                                    

   value  freq   perc  cumfreq  cumperc
1      0    31  50.0%       31    50.0%
2      1    31  50.0%       62   100.0%

' 95%-CI (classic)

────────────────────────────────────────────────────────────────────────────── 
3 - tamanho (numeric)

  length      n    NAs  unique    0s   mean  meanCI'
      62     57      5      28     0   4.34    3.32
          91.9%   8.1%          0.0%           5.37
                                                   
     .05    .10    .25  median   .75    .90     .95
    0.64   1.00   1.90    3.00  6.00  10.00   10.80
                                                   
   range     sd  vcoef     mad   IQR   skew    kurt
   18.70   3.86   0.89    2.22  4.10   1.70    2.90
                                                   
lowest : 0.3, 0.4 (2), 0.7 (2), 1.0 (2), 1.5 (6)
highest: 9.0, 10.0 (4), 14.0, 15.0, 19.0

' 95%-CI (classic)

────────────────────────────────────────────────────────────────────────────── 
4 - tamanhotumor (character - dichotomous)

  length      n    NAs unique
      62     57      5      2
          91.9%   8.1%       

                 freq   perc  lci.95  uci.95'
pequeno (< 3cm)    31  54.4%   41.6%   66.6%
grande (> 3cm)     26  45.6%   33.4%   58.4%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
5 - porte (character)

  length      n    NAs unique levels  dupes
      62     62      0      3      3      y
         100.0%   0.0%                     

     level  freq   perc  cumfreq  cumperc
1    Médio    27  43.5%       27    43.5%
2   Grande    18  29.0%       45    72.6%
3  Pequeno    17  27.4%       62   100.0%

────────────────────────────────────────────────────────────────────────────── 
6 - temraca (character - dichotomous)

  length      n    NAs unique
      62     62      0      2
         100.0%   0.0%       

     freq   perc  lci.95  uci.95'
SRD    34  54.8%   42.5%   66.6%
CRD    28  45.2%   33.4%   57.5%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
7 - raca (character)

  length      n    NAs unique levels  dupes
      62     62      0     11     11      y
         100.0%   0.0%                     

                 level  freq   perc  cumfreq  cumperc
1                  SRD    34  54.8%       34    54.8%
2         Outras Raças    10  16.1%       44    71.0%
3                Boxer     3   4.8%       47    75.8%
4   Labrador Retriever     3   4.8%       50    80.6%
5       Cocker Spaniel     2   3.2%       52    83.9%
6            Dachshund     2   3.2%       54    87.1%
7             Pinscher     2   3.2%       56    90.3%
8               Poodle     2   3.2%       58    93.5%
9    Yorkshire Terrier     2   3.2%       60    96.8%
10    Golden Retriever     1   1.6%       61    98.4%
11            Shih-Tzu     1   1.6%       62   100.0%

────────────────────────────────────────────────────────────────────────────── 
8 - sexo (character - dichotomous)

  length      n    NAs unique
      62     62      0      2
         100.0%   0.0%       

       freq   perc  lci.95  uci.95'
Fêmea    39  62.9%   50.5%   73.8%
Macho    23  37.1%   26.2%   49.5%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
9 - alimentacao (character)

  length      n    NAs unique levels  dupes
      62     62      0      4      4      y
         100.0%   0.0%                     

                                level  freq   perc  cumfreq  cumperc
1                        Apenas Ração    30  48.4%       30    48.4%
2  Mista (Ração + Comida ou petiscos)    29  46.8%       59    95.2%
3                       Apenas comida     2   3.2%       61    98.4%
4                       Não informado     1   1.6%       62   100.0%

────────────────────────────────────────────────────────────────────────────── 
10 - escorecorporal (character)

  length      n    NAs unique levels  dupes
      62     61      1      4      4      y
          98.4%   1.6%                     

                  level  freq   perc  cumfreq  cumperc
1   Acima do peso ideal    31  50.8%       31    50.8%
2            Peso ideal    16  26.2%       47    77.0%
3             Obesidade    12  19.7%       59    96.7%
4  Abaixo do peso ideal     2   3.3%       61   100.0%

────────────────────────────────────────────────────────────────────────────── 
11 - quimioterapia (character - dichotomous)

  length      n    NAs unique
      62     62      0      2
         100.0%   0.0%       

     freq   perc  lci.95  uci.95'
Não    38  61.3%   48.8%   72.4%
Sim    24  38.7%   27.6%   51.2%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
12 - grau_histologico (character - dichotomous)

  length      n    NAs unique
      62     53      9      2
          85.5%  14.5%       

            freq   perc  lci.95  uci.95'
baixo grau    33  62.3%   48.8%   74.1%
alto grau     20  37.7%   25.9%   51.2%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
13 - metastase (character - dichotomous)

  length      n    NAs unique
      62     62      0      2
         100.0%   0.0%       

     freq   perc  lci.95  uci.95'
Não    46  74.2%   62.1%   83.4%
Sim    16  25.8%   16.6%   37.9%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
14 - raca_2 (character)

  length      n    NAs unique levels  dupes
      62     62      0     11     11      y
         100.0%   0.0%                     

                 level  freq   perc  cumfreq  cumperc
1                  SRD    34  54.8%       34    54.8%
2         Outras Raças    10  16.1%       44    71.0%
3                Boxer     3   4.8%       47    75.8%
4   Labrador Retriever     3   4.8%       50    80.6%
5       Cocker Spaniel     2   3.2%       52    83.9%
6            Dachshund     2   3.2%       54    87.1%
7             Pinscher     2   3.2%       56    90.3%
8               Poodle     2   3.2%       58    93.5%
9    Yorkshire Terrier     2   3.2%       60    96.8%
10    Golden Retriever     1   1.6%       61    98.4%
11            Shih-Tzu     1   1.6%       62   100.0%

────────────────────────────────────────────────────────────────────────────── 
15 - margens_livres (character - dichotomous)

  length      n    NAs unique
      62     42     20      2
          67.7%  32.3%       

     freq   perc  lci.95  uci.95'
Não    38  90.5%   77.9%   96.2%
Sim     4   9.5%    3.8%   22.1%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
16 - status (numeric)

  length       n    NAs  unique     0s   mean  meanCI'
      62      62      0       2     15   0.76    0.65
          100.0%   0.0%          24.2%           0.87
                                                     
     .05     .10    .25  median    .75    .90     .95
    0.00    0.00   1.00    1.00   1.00   1.00    1.00
                                                     
   range      sd  vcoef     mad    IQR   skew    kurt
    1.00    0.43   0.57    0.00   0.00  -1.18   -0.63
                                                     

   value  freq   perc  cumfreq  cumperc
1      0    15  24.2%       15    24.2%
2      1    47  75.8%       62   100.0%

' 95%-CI (classic)

────────────────────────────────────────────────────────────────────────────── 
17 - data_inicial (POSIXct, POSIXt)

$xname
[1] "data_inicial"

$label
NULL

$class
[1] "POSIXct"

$classlabel
[1] "POSIXct, POSIXt"

$length
[1] 62

$n
[1] 62

$NAs
[1] 0

$main
[1] "17 - data_inicial (POSIXct, POSIXt)"

[[9]]
[1] "unhandled class"

────────────────────────────────────────────────────────────────────────────── 
18 - data_final (POSIXct, POSIXt)

$xname
[1] "data_final"

$label
NULL

$class
[1] "POSIXct"

$classlabel
[1] "POSIXct, POSIXt"

$length
[1] 62

$n
[1] 62

$NAs
[1] 0

$main
[1] "18 - data_final (POSIXct, POSIXt)"

[[9]]
[1] "unhandled class"

────────────────────────────────────────────────────────────────────────────── 
19 - tempo (numeric)

    length       n     NAs  unique        0s      mean    meanCI'
        62      62       0      60         0    616.03    457.20
            100.0%    0.0%              0.0%              774.87
                                                                
       .05     .10     .25  median       .75       .90       .95
     36.20   52.40  120.75  355.00  1'174.25  1'543.00  1'821.30
                                                                
     range      sd   vcoef     mad       IQR      skew      kurt
  2'124.00  625.46    1.02  421.80  1'053.50      0.89     -0.53
                                                                
lowest : 11.0, 13.0, 23.0, 36.0, 40.0
highest: 1'694.0, 1'828.0, 1'973.0, 2'110.0, 2'135.0

' 95%-CI (classic)

────────────────────────────────────────────────────────────────────────────── 
20 - escorecorporal_binario (factor - dichotomous)

  length      n    NAs unique
      62     61      1      2
          98.4%   1.6%       

                    freq   perc  lci.95  uci.95'
Peso Não Excedente    18  29.5%   19.6%   41.9%
Excesso de Peso       43  70.5%   58.1%   80.4%

' 95%-CI (Wilson)

────────────────────────────────────────────────────────────────────────────── 
21 - fct_relevel(escorecorporal_binario, "Peso Não Excedente") (factor - dichotomous)

  length      n    NAs unique
      62     61      1      2
          98.4%   1.6%       

                    freq   perc  lci.95  uci.95'
Peso Não Excedente    18  29.5%   19.6%   41.9%
Excesso de Peso       43  70.5%   58.1%   80.4%

' 95%-CI (Wilson)

Curvas Kaplan Mayer

Código
km_overall <- survfit(Surv(time = tempo, event = status) ~ 1, data = ds)

plot_km_overall <- ggsurvplot(km_overall,  data = ds,  risk.table = F,  pval = TRUE,  conf.int = TRUE,  xlab = "Time (Days)",  ylab = "Survival Probability")

plot_km_overall

Castracao

Código
km_by_castracao <- survfit(Surv(time = tempo, event = status) ~ castracao, data = ds)
plot_km_by_castracao <- ggsurvplot(
  km_by_castracao,
  data = ds,
  risk.table = F,
  pval = F,
  pval.method = F, 
  conf.int = F,
  xlab = "Time (Days)",
  ylab = "Survival Probability",
  legend.labs = c('Intact', 'Neutered'),
  legend.title = 'Neutering',
  font.x = c(16, 'bold'), 
  font.y = c(16, 'bold'),
  font.tickslab = 14,
  font.legend = c(16, 'bold')
)
plot_km_by_castracao

Grau histologico

Código
km_by_grau_hist <- survfit(Surv(time = tempo, event = status) ~ grau_histologico, data = ds)
plot_km_by_grau_hist <- ggsurvplot(
  km_by_grau_hist,
  data = ds,
  risk.table = F,
  pval = F,
  pval.method = F, 
  conf.int = F,
  xlab = "Time (Days)",
  ylab = "Survival Probability",
  legend.labs = c('Low', 'High'),
  legend.title = 'Histological grade',
  font.x = c(16, 'bold'), 
  font.y = c(16, 'bold'),
  font.tickslab = 14,
  font.legend = c(16, 'bold')
)
plot_km_by_grau_hist

Metastase

Código
km_by_metastase <- survfit(Surv(time = tempo, event = status) ~ metastase, data = ds)
plot_km_by_metastase <- ggsurvplot(
  km_by_metastase,
  data = ds,
  risk.table = F,
  pval = F,
  pval.method = F, 
  conf.int = F,
  xlab = "Time (Days)",
  ylab = "Survival Probability",
  legend.labs = c('Abscence', 'Presence'),
  legend.title = 'Metastasis',
  font.x = c(16, 'bold'), 
  font.y = c(16, 'bold'),
  font.tickslab = 14,
  font.legend = c(16, 'bold')
)
plot_km_by_metastase

Tamanho categórico

Código
km_by_tamanho <- survfit(Surv(time = tempo, event = status) ~ tamanhotumor, data = ds)
plot_km_by_tamanho <- ggsurvplot(
  km_by_tamanho,
  data = ds,
  risk.table = F,
  pval = F,
  pval.method = F, 
  conf.int = F,
  xlab = "Time (Days)",
  ylab = "Survival Probability",
  legend.labs = c('> 3cm', '< 3cm'),
  legend.title = 'Size',
  font.x = c(16, 'bold'), 
  font.y = c(16, 'bold'),
  font.tickslab = 14,
  font.legend = c(16, 'bold')
)
plot_km_by_tamanho

Criando os modelos univariados

Código
preditores <- c("castracao", "tamanhotumor", "grau_histologico", "metastase", 'porte', 'temraca', 'sexo', 'alimentacao', 'escorecorporal_binario')

uni_models <- map_df(preditores, ~ {
  formula_str <- paste("Surv(time = tempo, event = status) ~", .x)
  model <- coxph(as.formula(formula_str), data = ds)
  tidy(model, exponentiate = TRUE, conf.int = TRUE) 
}) %>%
  mutate(p.value = round(p.value, 2),
         estimate = round(estimate, 2),
         std.error = round(std.error,2),
         statistic = round(statistic,2),
         conf.low = round(conf.low,2),
         conf.high = round(conf.high,2)
         ) %>%
  arrange(p.value)

print(uni_models, n = 50)
# A tibble: 12 × 7
   term                  estimate std.error statistic p.value conf.low conf.high
   <chr>                    <dbl>     <dbl>     <dbl>   <dbl>    <dbl>     <dbl>
 1 grau_histologicobaix…     0.32      0.34     -3.38    0        0.16      0.62
 2 tamanhotumorpequeno …     0.44      0.31     -2.66    0.01     0.24      0.8 
 3 porteMédio                0.63      0.35     -1.31    0.19     0.31      1.26
 4 alimentacaoNão infor…     5.29      1.27      1.31    0.19     0.44     64.0 
 5 metastaseSim              1.5       0.32      1.26    0.21     0.8       2.81
 6 sexoMacho                 1.42      0.3       1.17    0.24     0.79      2.56
 7 escorecorporal_binar…     0.71      0.32     -1.05    0.29     0.38      1.34
 8 castracao                 0.79      0.3      -0.79    0.43     0.44      1.42
 9 alimentacaoMista (Ra…     0.57      0.75     -0.74    0.46     0.13      2.48
10 alimentacaoApenas Ra…     0.69      0.74     -0.5     0.62     0.16      2.96
11 temracaSRD                1.15      0.3       0.47    0.64     0.64      2.07
12 portePequeno              0.91      0.37     -0.24    0.81     0.44      1.9 

A tabela acima mostra os resultados para cada modelo univariado. Todos com exceção de castração foram significativos, partindo da referencia de p<0.25. Portanto, todos irão para o modelo multivariado.

Modelo multivariado

Código
multi_model_cph <- coxph(
  Surv(time = tempo, event = status) ~ tamanhotumor + grau_histologico + metastase + porte + temraca + sexo + alimentacao + escorecorporal_binario,
  data = ds,
  x = TRUE, y = TRUE
)


multi_results <- tidy(multi_model_cph, exponentiate = TRUE, conf.int = TRUE) %>% 
  mutate(p.value = round(p.value, 2),
         estimate = round(estimate, 2),
         std.error = round(std.error,2),
         statistic = round(statistic,2),
         conf.low = round(conf.low,2),
         conf.high = round(conf.high,2)
         ) %>%
  arrange(p.value)

multi_results

Validação do modelo

Código
## Proportional hazard assumption

ph_test <- cox.zph(multi_model_cph)
ph_test
                         chisq df      p
tamanhotumor            0.6926  1 0.4053
grau_histologico        2.6757  1 0.1019
metastase               0.0574  1 0.8106
porte                   0.7570  2 0.6849
temraca                 0.0972  1 0.7553
sexo                    2.9147  1 0.0878
alimentacao             4.7021  3 0.1950
escorecorporal_binario  5.1815  1 0.0228
GLOBAL                 26.8806 11 0.0048

A tabela acima não apresenta nenhum p significativo, o que indica que atendemos o pressuposto da proporcionalidade do risco.

Performance do modelo

Código
performance::model_performance(multi_model_cph) %>% flextable::flextable() %>% flextable::colformat_double(digits = 2)

AIC

AICc

BIC

R2_Nagelkerke

RMSE

Sigma

247.99

254.76

269.24

0.35

0.74

0.00