dimanche 12 avril 2020

[R][RStudio] Créer une Table 1 et l'exporter dans Word

Voici un NoteBook pour apprendre à créer une Table 1 sur R, et l'exporter dans Word

N'hésitez pas à le diffuser, sans oublier de citer la source.

Table 1 NoteBook
Rédacteur de ce NoteBook : Nathan El Bèze
ATTENTION : pour faciliter la lecture de ce tutoriel, nous allons assumer que les conditions de validité des principaux tests (Chi2 et Student) sont respectés. Il vous faudra bien entendu les vérifier de votre côté.
Nous allons commencer par récupérer un dataframe sur Kaggle concernant le risque cardiovasculaire :
https://www.kaggle.com/yassinehamdaoui1/cardiovascular-disease/download/ds3WrBuyDewR9rMbNdTR%2Fversions%2FNWMwUpq65Kh9rqczUgk0%2Ffiles%2Fcardiovascular.txt
On va également installer les différents packages dont on aura besoin à savoir - tableOne - officer - flextable - magrittr
On ouvre le dataframe
setwd("~/destination")
Database <- read.table("cardiovascular.txt", header = TRUE, sep = ";")
str(Database)
## 'data.frame':    462 obs. of  11 variables:
##  $ ind      : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ sbp      : int  160 144 118 170 134 132 142 114 114 132 ...
##  $ tobacco  : num  12 0.01 0.08 7.5 13.6 6.2 4.05 4.08 0 0 ...
##  $ ldl      : num  5.73 4.41 3.48 6.41 3.5 6.47 3.38 4.59 3.83 5.8 ...
##  $ adiposity: num  23.1 28.6 32.3 38 27.8 ...
##  $ famhist  : Factor w/ 2 levels "Absent","Present": 2 1 2 2 2 2 1 2 2 2 ...
##  $ typea    : int  49 55 52 51 60 62 59 62 49 69 ...
##  $ obesity  : num  25.3 28.9 29.1 32 26 ...
##  $ alcohol  : num  97.2 2.06 3.81 24.26 57.34 ...
##  $ age      : int  52 63 46 58 49 45 38 58 29 53 ...
##  $ chd      : int  1 1 0 1 1 0 0 1 0 1 ...
On va supprimer la première colonne, qui est l’identifiant du patient
Database = Database[,-1]
str(Database)
## 'data.frame':    462 obs. of  10 variables:
##  $ sbp      : int  160 144 118 170 134 132 142 114 114 132 ...
##  $ tobacco  : num  12 0.01 0.08 7.5 13.6 6.2 4.05 4.08 0 0 ...
##  $ ldl      : num  5.73 4.41 3.48 6.41 3.5 6.47 3.38 4.59 3.83 5.8 ...
##  $ adiposity: num  23.1 28.6 32.3 38 27.8 ...
##  $ famhist  : Factor w/ 2 levels "Absent","Present": 2 1 2 2 2 2 1 2 2 2 ...
##  $ typea    : int  49 55 52 51 60 62 59 62 49 69 ...
##  $ obesity  : num  25.3 28.9 29.1 32 26 ...
##  $ alcohol  : num  97.2 2.06 3.81 24.26 57.34 ...
##  $ age      : int  52 63 46 58 49 45 38 58 29 53 ...
##  $ chd      : int  1 1 0 1 1 0 0 1 0 1 ...
On va également changer le tabac et l’obésité en variables binaires
Database$tobacco = ifelse(Database$tobacco=="0","0","1")
Database$obesity = ifelse(Database$obesity<30,"0","1")
str(Database)
## 'data.frame':    462 obs. of  10 variables:
##  $ sbp      : int  160 144 118 170 134 132 142 114 114 132 ...
##  $ tobacco  : chr  "1" "1" "1" "1" ...
##  $ ldl      : num  5.73 4.41 3.48 6.41 3.5 6.47 3.38 4.59 3.83 5.8 ...
##  $ adiposity: num  23.1 28.6 32.3 38 27.8 ...
##  $ famhist  : Factor w/ 2 levels "Absent","Present": 2 1 2 2 2 2 1 2 2 2 ...
##  $ typea    : int  49 55 52 51 60 62 59 62 49 69 ...
##  $ obesity  : chr  "0" "0" "0" "1" ...
##  $ alcohol  : num  97.2 2.06 3.81 24.26 57.34 ...
##  $ age      : int  52 63 46 58 49 45 38 58 29 53 ...
##  $ chd      : int  1 1 0 1 1 0 0 1 0 1 ...
On voit ici que nos variables factorielles ne sont pas sous formes de facteur On a plusieurs manières de procéder, mais on va faire ainsi :
varsToFactor <- c("tobacco", "obesity", "chd")
Database[varsToFactor] <- lapply(Database[varsToFactor], factor)
str(Database)
## 'data.frame':    462 obs. of  10 variables:
##  $ sbp      : int  160 144 118 170 134 132 142 114 114 132 ...
##  $ tobacco  : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 1 1 ...
##  $ ldl      : num  5.73 4.41 3.48 6.41 3.5 6.47 3.38 4.59 3.83 5.8 ...
##  $ adiposity: num  23.1 28.6 32.3 38 27.8 ...
##  $ famhist  : Factor w/ 2 levels "Absent","Present": 2 1 2 2 2 2 1 2 2 2 ...
##  $ typea    : int  49 55 52 51 60 62 59 62 49 69 ...
##  $ obesity  : Factor w/ 2 levels "0","1": 1 1 1 2 1 2 1 1 1 2 ...
##  $ alcohol  : num  97.2 2.06 3.81 24.26 57.34 ...
##  $ age      : int  52 63 46 58 49 45 38 58 29 53 ...
##  $ chd      : Factor w/ 2 levels "0","1": 2 2 1 2 2 1 1 2 1 2 ...
On a fini de préparer les données
La variable qui nous intéresse ici est “chd” à savoir maladie cardiovasculaire. On va créer une table 1 en s’intéressant à 2 groupes : antécédent familial oui/non
On va en profiter pour récupérer le nom de toutes nos variables
dput(names(Database))
## c("sbp", "tobacco", "ldl", "adiposity", "famhist", "typea", "obesity", 
## "alcohol", "age", "chd")
On fait un copier coller de la réponse et on les mets dans un vecteur donc on aura besoin pour créer la table. On retire la variable de stratification (donc on ne met pas famhist)
MyVars = c("sbp", "tobacco", "ldl", "adiposity", "typea", "obesity", 
"alcohol", "age", "chd")
Pour faire cela on va faire en 3 étapes
  1. On créé la table 1 globale
library(tableone)
tab1a <- CreateTableOne(vars = MyVars, data = Database)
tab1a <- print(tab1a, quote = FALSE, noSpaces = TRUE, printToggle = FALSE, showAllLevels = TRUE)
tab1a
##                        
##                         level Overall         
##   n                     ""    "462"           
##   sbp (mean (SD))       ""    "138.33 (20.50)"
##   tobacco (%)           "0"   "107 (23.2)"    
##                         "1"   "355 (76.8)"    
##   ldl (mean (SD))       ""    "4.74 (2.07)"   
##   adiposity (mean (SD)) ""    "25.41 (7.78)"  
##   typea (mean (SD))     ""    "53.10 (9.82)"  
##   obesity (%)           "0"   "389 (84.2)"    
##                         "1"   "73 (15.8)"     
##   alcohol (mean (SD))   ""    "17.04 (24.48)" 
##   age (mean (SD))       ""    "42.82 (14.61)" 
##   chd (%)               "0"   "302 (65.4)"    
##                         "1"   "160 (34.6)"
  1. On créée la table 1 par groupe
tab1b <- CreateTableOne(vars = MyVars, strata = "famhist", data = Database)
tab1b <- print(tab1b, quote = FALSE, noSpaces = TRUE, printToggle = FALSE, showAllLevels = TRUE)
tab1b
##                        Stratified by famhist
##                         level Absent           Present          p        test
##   n                     ""    "270"            "192"            ""       ""  
##   sbp (mean (SD))       ""    "136.85 (20.58)" "140.41 (20.25)" "0.066"  ""  
##   tobacco (%)           "0"   "74 (27.4)"      "33 (17.2)"      "0.014"  ""  
##                         "1"   "196 (72.6)"     "159 (82.8)"     ""       ""  
##   ldl (mean (SD))       ""    "4.46 (2.03)"    "5.14 (2.07)"    "<0.001" ""  
##   adiposity (mean (SD)) ""    "24.22 (7.89)"   "27.08 (7.33)"   "<0.001" ""  
##   typea (mean (SD))     ""    "52.73 (9.94)"   "53.62 (9.64)"   "0.337"  ""  
##   obesity (%)           "0"   "236 (87.4)"     "153 (79.7)"     "0.035"  ""  
##                         "1"   "34 (12.6)"      "39 (20.3)"      ""       ""  
##   alcohol (mean (SD))   ""    "15.38 (21.62)"  "19.38 (27.91)"  "0.084"  ""  
##   age (mean (SD))       ""    "39.87 (15.30)"  "46.96 (12.48)"  "<0.001" ""  
##   chd (%)               "0"   "206 (76.3)"     "96 (50.0)"      "<0.001" ""  
##                         "1"   "64 (23.7)"      "96 (50.0)"      ""       ""
  1. On va maintenant sortir une belle table Word
tab1f = cbind(as.data.frame(tab1a), as.data.frame(tab1b))
Ici on a créé un dataframe (car la fonction que l’on va utiliser prend un dataframe en argument) qui réunit les 2 tables
Je vous encourage à ouvrir le DataFrame avec la fonction :
View(tab1f)
On va faire quelques manipulations à savoir
  • On va retirer la colonne test qui ne sert à rien, et la seconde colonne level qui est redondante (on voit que ce sont les colonnes 3 et 7)
tab1f = tab1f[,-c(3,7)]
D’autre part, on voit que le nom des variables n’est pas une colonne à part entière, donc on va créer cette colonne (on en a besoin pour la suite)
tab1f <- cbind(Variable = rownames(tab1f), tab1f)
On peut maintenant créer notre table (NB : un document Word temporaire va s’ouvrir, il lui manquera un peu de maquillage qu’il faudra faire à la main)
library(officer)
library(flextable)
library(magrittr)
ft <- flextable(data = tab1f) %>% 
  autofit
tmp <- tempfile(fileext = ".docx")
read_docx() %>% 
  body_add_flextable(ft) %>% 
  print(target = tmp)
browseURL(tmp)
ft
Variable
level
Overall
Absent
Present
p
n
462
270
192
sbp..mean..SD..
138.33 (20.50)
136.85 (20.58)
140.41 (20.25)
0.066
tobacco....
0
107 (23.2)
74 (27.4)
33 (17.2)
0.014
X
1
355 (76.8)
196 (72.6)
159 (82.8)
ldl..mean..SD..
4.74 (2.07)
4.46 (2.03)
5.14 (2.07)
<0.001
adiposity..mean..SD..
25.41 (7.78)
24.22 (7.89)
27.08 (7.33)
<0.001
typea..mean..SD..
53.10 (9.82)
52.73 (9.94)
53.62 (9.64)
0.337
obesity....
0
389 (84.2)
236 (87.4)
153 (79.7)
0.035
X.1
1
73 (15.8)
34 (12.6)
39 (20.3)
alcohol..mean..SD..
17.04 (24.48)
15.38 (21.62)
19.38 (27.91)
0.084
age..mean..SD..
42.82 (14.61)
39.87 (15.30)
46.96 (12.48)
<0.001
chd....
0
302 (65.4)
206 (76.3)
96 (50.0)
<0.001
X.2
1
160 (34.6)
64 (23.7)
96 (50.0)
Voici ce que vous allez avoir sur Word. Il faut un peu de maquillage, mais l’essentiel du travail est fait.