Il y a quelque temps, j’ai publié un article pour vous montrer comment réaliser une table descriptive, dite Table 1, avec le package Table1.
Mais plusieurs lecteurs (et lectrices 😉 ) m’ont écrit pour me dire qu’ils rencontraient des difficultés pour installer ce package, car il n’est pas sur CRAN. En effet, actuellement pour le moins, ce package doit être téléchargé à partir d’un répertoire Github. Et les restrictions informatiques des certaines organisations (facultés, entreprises, etc…) ne permettent pas toujours (ou plus difficilement) ce type de téléchargement.
Je vous propose donc une autre solution : utiliser le package tableone
!
Ce package est téléchargeable sur CRAN, il permet de faire de belles tables one, et en plus les sorties sont facilement exportables en format csv !
Quoi demander de plus ?
De pouvoir choisir de présenter la moyenne et l’écart-type, ou la médiane et l’intervalle inter-quartile selon si les variables quantitatives suivent, ou pas une distribution normale ?
Eh bien, il le fait aussi ! Si si ….. Je vous montre tout ça en pas à pas.
Nous allons employer les données cgd
du package survival
. Les données proviennent d’un essai contrôlé par placebo sur l’interféron gamma dans la maladie granulotomique chronique (CGD).
install.packages(survival)
library(survival)
str(cgd)
## 'data.frame': 203 obs. of 16 variables:
## $ id : int 1 1 1 2 2 2 2 2 2 2 ...
## $ center : Factor w/ 13 levels "Harvard Medical Sch",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ random : Date, format: "1989-06-07" "1989-06-07" ...
## $ treat : Factor w/ 2 levels "placebo","rIFN-g": 2 2 2 1 1 1 1 1 1 1 ...
## $ sex : Factor w/ 2 levels "male","female": 2 2 2 1 1 1 1 1 1 1 ...
## $ age : int 12 12 12 15 15 15 15 15 15 15 ...
## $ height : num 147 147 147 159 159 159 159 159 159 159 ...
## $ weight : num 62 62 62 47.5 47.5 47.5 47.5 47.5 47.5 47.5 ...
## $ inherit : Factor w/ 2 levels "X-linked","autosomal": 2 2 2 2 2 2 2 2 2 2 ...
## $ steroids: num 0 0 0 0 0 0 0 0 0 0 ...
## $ propylac: num 0 0 0 1 1 1 1 1 1 1 ...
## $ hos.cat : Factor w/ 4 levels "US:NIH","US:other",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ tstart : int 0 219 373 0 8 26 152 241 249 322 ...
## $ enum : int 1 2 3 1 2 3 4 5 6 7 ...
## $ tstop : int 219 373 414 8 26 152 241 249 322 350 ...
## $ status : int 1 1 0 1 1 1 1 1 1 1 ...
Le principe est assez simple :
CreateTableOne()
print()
avec différents arguments pour modifier la table one créée :library(dplyr)
mydata <- cgd %>%
dplyr::select(treat :hos.cat)
str(mydata)
## 'data.frame': 203 obs. of 9 variables:
## $ treat : Factor w/ 2 levels "placebo","rIFN-g": 2 2 2 1 1 1 1 1 1 1 ...
## $ sex : Factor w/ 2 levels "male","female": 2 2 2 1 1 1 1 1 1 1 ...
## $ age : int 12 12 12 15 15 15 15 15 15 15 ...
## $ height : num 147 147 147 159 159 159 159 159 159 159 ...
## $ weight : num 62 62 62 47.5 47.5 47.5 47.5 47.5 47.5 47.5 ...
## $ inherit : Factor w/ 2 levels "X-linked","autosomal": 2 2 2 2 2 2 2 2 2 2 ...
## $ steroids: num 0 0 0 0 0 0 0 0 0 0 ...
## $ propylac: num 0 0 0 1 1 1 1 1 1 1 ...
## $ hos.cat : Factor w/ 4 levels "US:NIH","US:other",..: 2 2 2 2 2 2 2 2 2 2 ...
Nous allons passer en facteur les variables steroids
et propylac
et les recoder :
mydata$steroids <- factor(mydata$steroids)
mydata$propylac <- factor(mydata$propylac)
library(forcats)
mydata$steroids <- fct_recode(mydata$steroids,
no="0",
yes="1")
mydata$propylac <- fct_recode(mydata$propylac,
no="0",
yes="1")
install.packages("tableone")
library(tableone)
CreateTableOne(data=mydata)
##
## Overall
## n 203
## treat = rIFN-g (%) 83 (40.9)
## sex = female (%) 35 (17.2)
## age (mean (SD)) 13.70 (9.34)
## height (mean (SD)) 138.12 (31.41)
## weight (mean (SD)) 39.34 (21.83)
## inherit = autosomal (%) 72 (35.5)
## steroids = yes (%) 7 ( 3.4)
## propylac = yes (%) 172 (84.7)
## hos.cat (%)
## US:NIH 41 (20.2)
## US:other 108 (53.2)
## Europe:Amsterdam 28 (13.8)
## Europe:other 26 (12.8)
Lorsqu’une variable qualitative n’a que deux modalités (par exemple trt
), seule la modalité de référence est spécifiée dans la table….
Ce n’est pas génial du tout !
Alors pour modifier cela nous devons :
print()
, avec l’argument showAllLevels = TRUE
table_globale <- CreateTableOne(data=mydata)
print(table_globale, showAllLevels = TRUE)
##
## level Overall
## n 203
## treat (%) placebo 120 (59.1)
## rIFN-g 83 (40.9)
## sex (%) male 168 (82.8)
## female 35 (17.2)
## age (mean (SD)) 13.70 (9.34)
## height (mean (SD)) 138.12 (31.41)
## weight (mean (SD)) 39.34 (21.83)
## inherit (%) X-linked 131 (64.5)
## autosomal 72 (35.5)
## steroids (%) no 196 (96.6)
## yes 7 ( 3.4)
## propylac (%) no 31 (15.3)
## yes 172 (84.7)
## hos.cat (%) US:NIH 41 (20.2)
## US:other 108 (53.2)
## Europe:Amsterdam 28 (13.8)
## Europe:other 26 (12.8)
C’est quand même vraiment mieux !
Ce qui est classique, c’est d’utiliser la moyenne et l’écart-type (ou sd) lorsque les données suivent une distribution normale, et la médiane et l’intervalle interquartile (IQR), si les données ne suivent pas une loi normale.
Afin d’obtenir les variables pour lesquelles le test de Shapiro-Wilk est significatif (rejet de l’hypothèse de normalité), nous pouvons employer ce code :
library(purrr)
mydata %>%
dplyr::select_if(is.numeric) %>%
as.list() %>%
map(shapiro.test)%>%
keep(~ .x$p.value < 0.05)
## $age
##
## Shapiro-Wilk normality test
##
## data: .x[[i]]
## W = 0.94104, p-value = 2.375e-07
##
##
## $height
##
## Shapiro-Wilk normality test
##
## data: .x[[i]]
## W = 0.94672, p-value = 7.804e-07
##
##
## $weight
##
## Shapiro-Wilk normality test
##
## data: .x[[i]]
## W = 0.93138, p-value = 3.609e-08
Ensuite, il est nécessaire de créer un vecteur avec le nom de ces variables, et de les spécifier dans la fonction print()
, avec l’argument nonnormal
, comme ceci :
var_non_normal <- c("age","height","weight")
print(table_globale ,
showAllLevels = TRUE,
nonnormal = var_non_normal)
##
## level Overall
## n 203
## treat (%) placebo 120 (59.1)
## rIFN-g 83 (40.9)
## sex (%) male 168 (82.8)
## female 35 (17.2)
## age (median [IQR]) 12.00 [6.00, 20.00]
## height (median [IQR]) 140.00 [114.50, 169.25]
## weight (median [IQR]) 33.40 [20.25, 58.70]
## inherit (%) X-linked 131 (64.5)
## autosomal 72 (35.5)
## steroids (%) no 196 (96.6)
## yes 7 ( 3.4)
## propylac (%) no 31 (15.3)
## yes 172 (84.7)
## hos.cat (%) US:NIH 41 (20.2)
## US:other 108 (53.2)
## Europe:Amsterdam 28 (13.8)
## Europe:other 26 (12.8)
Ici, je vais utiliser la variable treat
comme variable de stratification :
table_strat <- CreateTableOne( strata = "treat" , data = mydata )
print(table_strat,
showAllLevels = TRUE,
nonnormal = var_non_normal,
test=FALSE)
Stratified by treat
level placebo rIFN-g
n 120 83
treat (%) placebo 120 (100.0) 0 ( 0.0)
rIFN-g 0 ( 0.0) 83 (100.0)
sex (%) male 100 ( 83.3) 68 ( 81.9)
female 20 ( 16.7) 15 ( 18.1)
age (median [IQR]) 11.50 [5.00, 21.25] 12.00 [7.00, 18.50]
height (median [IQR]) 140.05 [107.85, 169.77] 140.00 [119.95, 166.50]
weight (median [IQR]) 33.40 [18.10, 63.55] 34.40 [22.25, 52.00]
inherit (%) X-linked 74 ( 61.7) 57 ( 68.7)
autosomal 46 ( 38.3) 26 ( 31.3)
steroids (%) no 114 ( 95.0) 82 ( 98.8)
yes 6 ( 5.0) 1 ( 1.2)
propylac (%) 0 20 ( 16.7) 11 ( 13.3)
1 100 ( 83.3) 72 ( 86.7)
hos.cat (%) US:NIH 20 ( 16.7) 21 ( 25.3)
US:other 67 ( 55.8) 41 ( 49.4)
Europe:Amsterdam 16 ( 13.3) 12 ( 14.5)
Europe:other 17 ( 14.2) 9 ( 10.8)
Vous pouvez choisir d’afficher les p-values des comparaisons entre les strates, en employant l’argument test=TRUE
et exact=TRUE
(permet de faire des tests de Fisher à la place des tests du Chi2, quand le nombre de données est trop faible)
print(table_strat,
showAllLevels = TRUE,
nonnormal = var_non_normal,
test=TRUE)
Stratified by treat
level placebo rIFN-g p
n 120 83
treat (%) placebo 120 (100.0) 0 ( 0.0) <0.001
rIFN-g 0 ( 0.0) 83 (100.0)
sex (%) male 100 ( 83.3) 68 ( 81.9) 0.943
female 20 ( 16.7) 15 ( 18.1)
age (median [IQR]) 11.50 [5.00, 21.25] 12.00 [7.00, 18.50] 0.750
height (median [IQR]) 140.05 [107.85, 169.77] 140.00 [119.95, 166.50] 0.632
weight (median [IQR]) 33.40 [18.10, 63.55] 34.40 [22.25, 52.00] 0.736
inherit (%) X-linked 74 ( 61.7) 57 ( 68.7) 0.381
autosomal 46 ( 38.3) 26 ( 31.3)
steroids (%) no 114 ( 95.0) 82 ( 98.8) 0.287
yes 6 ( 5.0) 1 ( 1.2)
propylac (%) 0 20 ( 16.7) 11 ( 13.3) 0.641
1 100 ( 83.3) 72 ( 86.7)
hos.cat (%) US:NIH 20 ( 16.7) 21 ( 25.3) 0.447
US:other 67 ( 55.8) 41 ( 49.4)
Europe:Amsterdam 16 ( 13.3) 12 ( 14.5)
Europe:other 17 ( 14.2) 9 ( 10.8)
Stratified by treat
test
n
treat (%)
sex (%)
age (median [IQR]) nonnorm
height (median [IQR]) nonnorm
weight (median [IQR]) nonnorm
inherit (%)
steroids (%)
propylac (%)
hos.cat (%)
Ici, je commence par créer un dossier “resultats”, puis j’exporte la table one, dans ce dossier, en employant la fonction write.csv2().
ma_table_strat <- print(table_strat,
showAllLevels = TRUE,
nonnormal = var_non_normal,
test=TRUE)
dir.create("resultats")
write.csv2(ma_table_strat, here::here("resultats/ma_table_strat.csv"))
Et voilà !
Je vous laisse essayer ce package, et n’hésitez pas à me faire des retours en laissant un commentaire.
Si vous voulez en savoir plus sur l’utilisation de ce package `tableone`, vous pouvez consulter sa vignette en cliquant ici.
Si cet article vous a plu, ou vous a été utile, vous pouvez le partager, et soutenir le blog en réalisant un don libre sur la page Tipeee.
Enregistrez vous pour recevoir gratuitement mes fiches “aide mémoire” (ou cheat sheets) qui vous permettront de réaliser facilement les principales analyses biostatistiques avec le logiciel R et pour être informés des mises à jour du site.
3 Responses
Bonjour,
savez-vous quels tests sont utilisés par défaut dans cette table ?
merci par avance et bravo pour ce magnifique blog !
David
Bonjour David,
dans la page d’aide de la fonction CreateTableOne, vous trouverez les infos suivantes :
testApprox = chisq.test,
argsApprox = list(correct = TRUE),
testExact = fisher.test,
argsExact = list(workspace = 2 * 10^5),
testNormal = oneway.test,
argsNormal = list(var.equal = TRUE),
testNonNormal = kruskal.test,
Je comprends que, par défaut, c’est un test t quand il ya 2 groupes et que les données sont quantitatives, une anova quand il y a plus de 2 groupes, et un test du chi2 pour les données qualitatives.
Je vous recommande de faire des tests pour être bien sûr (notamment pour vérifier l’utilisation de l’anova ou du test de Kruskall Wallis).
Vous pouvez aussi jeter un coup d’oeil au package gtsummary que j’utilise à présent.
Bonne continuation.
Bonjour, merci beaucoup pour ces efforts.
Dis moi y’a t’il un script pour associer l’apparition des lettres pour la séparation des médianes de Dunntest du packages FSA???