Skip to content

Standardisation sortie modele Cox#44

Open
AckaFun wants to merge 3 commits into
mainfrom
28-standardisation-des-sorties-de-modeles
Open

Standardisation sortie modele Cox#44
AckaFun wants to merge 3 commits into
mainfrom
28-standardisation-des-sorties-de-modeles

Conversation

@AckaFun
Copy link
Copy Markdown
Contributor

@AckaFun AckaFun commented Jan 3, 2025

  • Trouver un nom pour xx
  • report_survit
  • ajouter des labels de colonnes
  • faire une jolie flextable
  • ajouter des exemples dans la doc
  • ajouter des tests (enlever les library())

notamment suppression de test_standardisation
@DanChaltiel
Copy link
Copy Markdown
Member

Fonctions principales dans flextable :

  • flextable() pour faire une flextable
  • bold(), italic(), color(), bg(), etc pour modifier le format
  • border(), vline(), hline() pour les bordures
  • merge_v() et merge_h() pour merger les cellules (aussi fix_border_issues() parfois)
  • set_table_properties(ft, width = .5, layout = "autofit")
  • add_header_row(), voire set_header_df() si header complexe
  • colformat_xxx() si besoin de formattage particulier. Permet de modifier la flextable sans transformer les données en character.
  • les arguments i et j en formule permettent de sélectionner des lignes et colonnes conditionnelement aux données, genre bold(i=~pvalue<0.05, j="pvalue"). Implique que pvalue soit numérique...

Cheat sheet très utile : https://ardata-fr.github.io/flextable-book/static/pdf/cheat_sheet_flextable.pdf

Documentation très très longue: https://ardata-fr.github.io/flextable-book/

@DanChaltiel DanChaltiel linked an issue Feb 17, 2025 that may be closed by this pull request
8 tasks
Comment thread tests/testthat/test-models.R Outdated
# On ne lance pas les fonctions on charge le package avec ctrl+shift+l
# Enlever les librarys d'ici

test_that("shit works", {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Watch your mouth young boy!

Mise à jour des avancées sur les sorties de modèle
Copy link
Copy Markdown
Member

@DanChaltiel DanChaltiel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nickel !
Au final jsp ce que j'ai dit la dernière fois, pour cette PR centrée sur Cox c'est largement suffisant de faire un tableau et un paragraphe.

Pour le tableau, cf. mes quelques commentaires, mais sinon c'est bon pour moi.

Pour report_coxph(), je pense qu'on peut l'améliorer, voici ce que j'ai utilisé pour mon dernier rapport.

  • Je n'ai eu aucun problème de HP donc il faudrait l'ajouter au texte.
  • J'ai essayé de détecter le type de pvalue mais je ne suis pas 100% sûr de moi.
  • C'est très axé médicament, il faut peut-être être plus souple dans le glue()
report_coxph = function(fit, label, conf.level=0.95, 
                        trt_term="ARMtreatment"){
  chk = fit %>% cox.zph() %>% .$table %>% as.data.frame() %>% filter(p<0.05)
  if(nrow(chk)>0){
    #TODO add coxzph in result if this ever happens, like "hypoth was met / violated"
    browser()
  }
  is_stratif = fit$terms %>% paste(collapse="--") %>% str_detect("strata\\(")
  p_type = if(is_stratif) "stratified" 
  else if(length(fit$coefficients)>1) "adjusted" 
  else "raw"

  a = broom::tidy(fit, conf.level=conf.level, exponentiate=TRUE, conf.int=TRUE) %>% 
    filter(term==trt_term) %>% 
    mutate(across(-term, ~round(.x, 2)))

  glue("In the Cox model, the Hazard Ratio of treatment for {label} was {a$estimate} [{100*conf.level}%CI {a$conf.low}; {a$conf.high}] ({p_type} p-value: {a$p.value}).")
}

Si tu veux, tu peux aussi ajouter une fonction de ce genre, on n'est pas strictement dans le Cox mais on reste dans le thème. Dans mon cas j'ai ajouté la pvalue mais pas sûr que ce soit bien, il faudrait le mettre NULL par défaut et gérer le cas.

report_survfit = function(fit, pval_stratif, time, label, ...){
  pval_stratif = pval_stratif
  sfit = summary(fit)
  
  #Brookmeyer-Crowley method for median CI
  med =
    sfit$table %>% 
    as_tibble(rownames="strata") %>% 
    select(strata, median, ci_inf="0.95LCL", ci_sup="0.95UCL") %>% 
    mutate(across(-strata, ~round(.x, 1)),
           strata = str_remove(strata, ".*="),
           label = if_else(is.na(median), "not attained",
                           glue("{median} [{ci_inf}; {ci_sup}]"))) %>% 
    glue_data("{label} in the {strata} arm")
  # all(is.na(sfit$table[,"median"]))
  par_med = format_inline("Median was {med}.")
  
  pars = tidy_survfit(fit, time=time, ...) %>% 
    select(strata, estimate, conf.low, conf.high) %>% 
    mutate(across(-strata, ~scales::percent(.x, 1))) %>% 
    glue_data("{estimate} [95%CI {conf.low}; {conf.high}] in the {strata} arm")
  par_surv = format_inline("{label} was {pars} (Log-rank stratified 2-sided p-value = {round(pval_stratif, 2)}).")
  
  c(par_surv, par_med)
}


a = broom::tidy(fit, exponentiate=TRUE, conf.int=TRUE) %>%
filter(substr(term, 1, nchar(arm))==arm) %>%
mutate(across(-term, ~round(.x, 2)))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format.pval() pour la pvalue

report_coxph = function(fit, label, arm){

a = broom::tidy(fit, exponentiate=TRUE, conf.int=TRUE) %>%
filter(substr(term, 1, nchar(arm))==arm) %>%
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

str_starts() ?

Comment on lines +18 to +20
HR = ifelse(is.na(conf.low),
'1.00',
glue("{format(round(estimate, 2), nsmall = 2)} [{round(conf.low, 2)};{round(conf.high, 2)}]"))) %>%
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

il faudrait ajouter un argument digits=2

Comment on lines +22 to +24
group_by(var_label) %>%
mutate(rep = row_number()) %>%
ungroup() %>%
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

il vaut mieux éviter d'utiliser group_by:
mutate(rep = row_number(), .by=var_label)

Comment on lines +30 to +37
attr(rtn, "header") =
c(
var_label = 'Variable',
label = '',
n = 'Number of events/N',
HR = 'HR [95% CI]',
p_new = 'p-value'
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pourquoi ne pas simplement utiliser apply_labels() ?

#' @export
#'
cox_regtable = function(fit){
rtn = tidy_plus_plus(fit, exponentiate = T, conf.int = T) %>%
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

La dépendance à broom::tidy n'est pas grave, mais tidy_plus_plus va ajouter pas mal de trucs.
Si on augmente les dépendances, l'installation de grstat prend 3 plombes.
On en a vraiment besoin ?



test_that("cox_regtable() works", {
local_reproducible_output(width=125)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utile seulement si tu fais un snapshot

Comment on lines +8 to +9
lung = survival::lung
fit = coxph(Surv(time, status) ~ as.factor(ph.ecog) + age, data=lung)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withr::with_package("survival", {
fit = coxph(Surv(time, status) ~ as.factor(sex) + age + strata(ph.ecog) + ph.karno, data=lung)
})

Attention, il faudra ajouter survival (et withr) dans les "Suggests" du fichier DESCRIPTION

Comment on lines +11 to +12
ald = cox_regtable(fit)
expect_s3_class(ald, "regtable")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintenant il faut ajouter des tests sur ald, sur as_flextable(ald), et sur report_coxph(fit).
Un snapshot sera sans doute suffisant.

#' @importFrom tidyr unite
#' @export
#'
cox_regtable = function(fit){
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je suis nul en naming, mais si on garde report_coxph() ce serait plus logique d'appeler ta fonction table_coxph() non ?
Ou alors report_cox et table_cox ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Standardisation des sorties de modeles

3 participants