Trucs pour LaTeX & R

Créer un tableau résumant votre étude

lundi 18 septembre 2017 par Philippe MICHEL

25/02/2017 : Amélioration de la définition du longtable (pas encore parfait)

Tables - code complet

Pour l’exemple nous allons créer un tableau habituel dans un article médical : comparaison de deux groupes (traités / non traités par exemple) en donnant pour chaque variable la moyenne & l’écart type pour les données numériques, le nombre & le pourcentage pour les données discrètes, enfin le p. Ce qui donne (en moche) :

traiténon traitép
Âge 55,2 $pm$ 10,5 48,7 +/- 14,5 0,04
Sexe = M 44/110 (35%) 48/112 (36%) 0,75

Le script peut se résumer à :

Initialisation du tableau
Pour chaque colonne :
     Si numérique :
          Calcul moyenne, écart-type, p.
          Création de la ligne & ajout au tableau
     Si variable discrète :
          Calcul des % pour chaque modalité & du chi2   
           Si dichotomique :
                      Création de la ligne & ajout au tableau
           Plus de deux niveau :
                      Ligne nom variable, p
                      Création de la ligne & ajout au tableau
                      Pour chaque valeur de la variable de tri :
                                  Ligne avec les n & %.
                                  Création de la ligne & ajout au tableau
création du titre (avec les niveaux de la variable de tri)
Transformation du tableau en LaTeX

Nous partons donc d’un data-frame nommé tt, bien préparé. Un tableau simple descriptif a déjà été réalisé. Nous allons créer un tableau reprenant toutes les variables, les comparer entre les différents groupes (il y a donc une variable de test appelée ici vtri & ayant deux niveaux oui & non). L’exemple a deux modalités ce qui est le cas le plus fréquent mais il peut il y en avoir plus. D’où l’utilisation d’une Anova pour la comparaison & non un simple Student.

l’affichage doit comprendre :

  • Pour les variables numériques : moyenne +/- écart type avec le bon symbole +/-
  • Pour les variables discrètes : nombre (pourcentage)
  • On verra aussi une variante avec un test non paramétrique (Wilcoxon) avec affichage des médianes & des quartiles.

Tout d’abord il faut initialiser la boucle qui va parcourir toutes les variables du data.frame & créer un tableau vide.

vtri la variable de tri
tt le data.frame étudié

      lvtri <- length(levels(vtri))# Nb de modalité de la variable de tri
      mlig <- matrix(nrow=0,ncol=lvtri+2)# création de la matrice
        #
        # ...
        # tout le traitement par ligne
        # ...
}
# Transformation du tableau en LaTeX grâce à xtable
xtable(tabf) # ... (voir plus bas)

une ligne moyenne écart-type

Nous allons donc calculer la moyenne & l’écart-type pour chacune des modalités de notre variable de test. La fonction agregate est là pour ça :

 aggregate(etude$age,by=list(traitement),FUN="mean",na.rm=T)
  Group.1        x
1     Non 38.47826
2     Oui 36.94286

Qui nous renvoie un tableau avec, en première colonne les niveaux de la variable de test & en seconde colonne la moyenne pour chacun de ces niveaux.

Comme il n’y a que deux niveaux on aurait pu utiliser le t de Student (la fonction t.test vous donne les moyennes des deux groupes comparées) mais aggregate a deux qualités : on utilisera la même méthode pour calculer l’écart-type & de plus on pourra faire des tableaux avec des variables de tri à plus deux niveaux.

Donc on va extraire les données du tableau. Créons donc une petite boucle qui va afficher la moyenne et l’écart-type :

vart est la colonne du data.frame en cours.
vtri la variable de tri

if (is.numeric(vart)){ print("num")
    agm <- aggregate(vart~vtri,FUN="mean",na.rm=T)
    ags <- aggregate(vart~vtri,FUN="sd",na.rm=T)
    for (j in 1:lvtri){ #pour chaque modalité
        moy <- round(agm[j,2],2)
        etyp <- round(ags[j,2],2)
        dlig <- c(dlig,paste0(moy,"\\pm ",etyp)) # On allonge la ligne
    }
    ll <- anova(lm(vart~vtri))[5]
    lla <-ll[1,1]
    lla <- signif(lla,3)
    dlig <- c(dlig,lla)
    tabf <- rbind(tabf,dlig) #ajout de la ligne au tableau
  }

En reprenant le code : On calcule les moyennes & les écarts-type ainsi que le nombre de niveau de la variable de tri (ici 2). Puis on initie la ligne (un vecteur) avec le nom de la variable (un peu bête dans cet exemple mais ça va servir plus tard). Dans la boucle on extrait pour chaque ligne le nombre voulu, on le formate pour avoir un affichage clair puis on l’ajoute à la ligne dans le vecteur.

Il ne reste qu’à faire un anova, en extraire le p & l’inclure dans le vecteur. Et voilà une belle ligne.

Non paramétrique

Le même pour un test non paramétrique & une présentation en médiane & quartiles. (ne fonctionne que pour deux modalités).

    if (is.numeric(vart)){
        qo <- quantile(vart[vtri=="oui"],na.rm=T)
         qn <- quantile(vart[vtri=="non"],na.rm=T)
         mo <- paste0(qo[3]," [",qo[2],"-",qo[4],"]")
         mn <- paste0(qn[3]," [",qn[2],"-",qn[4],"]")
        dlig <- c(dlig,mo,mn) # On allonge la ligne
    ll <- wilcox.test(vart~vtri)
    ll <- ll$p.value
    lla <- signif(ll,3)
    dlig <- c(dlig,lla)
      mlig <- rbind(mlig,dlig) #ajout de la ligne au tableau
  }

Une ligne nombre/pourcentage

Nous allons un peu compliquer les choses : nous allons avoir un affichage simple sur une ligne pour les variables dichotomiques en affichant une seule modalité. L’en-tête de la ligne sera donc le nom de la variable suivi de la modalité affichée sauf si l’on est en Oui/Non auquel cas on affiche le Oui.

Si la variable a plus de deux modalités on affiche une ligne avec son nom & le p global, ensuite la répartition modalité par modalité :

Sexe (M)44(55%)48 (48%)0,45
Hypertendu 88 (74 %) 54 (47 %) 0,054
Couleur des cheveux 0,88
_____blond 45 (55 %) 48 (57 %)
_____brun 38 (35 %) 47 (36 %)
_____roux 5 (10 %) 35 (7 %)

Je vous laisse rendre le résultat lisible en LaTeX en jouant sur des traits, des couleurs etc.

Petit préalable : toutes les variables factorielles en Oui/Non doivent être transformés au préalable en variable ordonnées avec Oui en premier niveau par :

> levels(vaccin)
[1] "Non" "Oui"
> vaccin <- relevel(vaccin,"Oui")
> levels(vaccin)
[1] "Oui" "Non"

Je vous laisse écrire la boucle avec un test pour appliquer ça à toute votre base de donnée.

         vart <- as.factor(vart)
            if (length(levels(vart))>1){ # On évite les valeurs constantes
       tb <- table(vtri,vart) # on crée un tableau croisé
       tbm <- margin.table(tb,1) # Sommes par ligne      
       clig <- chisq.test(vart,vtri)$p.value  # Calcul du Chi2
           clig <- signif(clig,3)
#
# Variables à 2 niveaux     
#
       if (length(levels(vart)) == 2){        
           if(levels(vart)[1] != "oui"){ # Complément du nom de variable
           dlig <- paste0(dlig, " (",levels(vart)[1],")")
       }
           for (j in 1:lvtri){
            nn <- tb[j,1]
            pn <- signif(100*nn/tbm[j],3)
            dlig <- c(dlig,paste0(nn," (",pn,"\\, \\%)"))   }    
          dlig <- c(dlig,clig)
          tabf <- rbind(tabf,dlig) #ajout de la ligne au tableau
                }
#
# Variables à plus de 2 niveaux     
#
            else { 
    tlig <- c(names(tt[l]),rep(" ",lvtri),clig)
    tabf <- rbind(tabf,tlig)
    for (i in 1:length(levels(vart))){ #Pour chaque niveau de la variable
        dlig <- paste0("~~~~~",levels(vart)[i])
        for (j in 1:lvtri){
            nn <- tb[j,i]
            pn <- signif(100*nn/tbm[j],3)
            dlig <- c(dlig,paste0(nn," (",pn,"\\, \\%)"))
        }
        dlig <- c(dlig," ")
        tabf <- rbind(tabf,dlig) #ajout de la ligne au tableau
    }}
}

On crée d’abord un tableau croisant la variable à étudier avec la variable tri, on calcule les totaux des lignes avec margin.table. la suite des calculs est simple, un chi2 pour finir, enfin on monte la ligne comme pour les moyennes.

Pour les variables a plus de deux niveaux on va d’abord créer la ligne contenant le nom de la variable , des cases vides & le p global puis la transformer en une matrice d’une ligne.
Ensuite une boucle va prendre toutes les modalités de la variable de test pour chacune créer une ligne, faire les calculs comme plus haut et ensuite ajouter cette ligne à la matrice (fonction rbind). Et voilà.

Construire le tableau

Il reste maintenant à transformer le tableau en LaTeX avec le bon en-tête.

  library(xtable) 
                                           #Création de la ligne de titre
    ltit <- paste0("&\\text{",paste(levels(vtri),collapse="}&\\text{"),"}&p\\\\")
                                          # Transformation du tableau en LaTeX via le package [*xtable*]
   xlig <- xtable(mlig) 
                                        #
        print(xlig,
              tabular.environment='longtable',
          include.colnames=FALSE,
          floating=FALSE,
          booktabs=TRUE,
          hline.after=-1,
          include.rownames=FALSE,
          sanitize.text.function = function(x){x},
          add.to.row = list(pos = list(0),
          command =
               paste0(ltit,
               " 
                \\midrule
                \\endfirsthead
                \\midrule
              ",
               ltit,
              "
               \\midrule
               \\endhead
               \\bottomrule
               \\endfoot
               \\bottomrule
               \\caption{} 
               \\label{tab}
               \\endlastfoot
              ")
      )
)     

Il reste à préciser la légende & le label. À moins de mettre dans la définition de fonction une variable pour le label.
Derneir problème : je n’ai toujours pas compris comment indiquer la composition des colonnes. Il sort donc quelque chose comme :

\begin{longtable}{llll}

à corriger manuellement, désolé ! Personnellement j’utilise une commande de défiinition de colonnes en mode math nommée « C » & le type « S » du package siunitx pour le petit p soit :

\newcolumntype{C}{>{$}c<{$}} 
.....
\begin{longtable}{lCCS}

À vous de jouer !


Accueil | Contact | Plan du site | | Statistiques du site | Visiteurs : 2412 / 148381

Suivre la vie du site fr  Suivre la vie du site kntitr   ?    |    titre sites syndiques OPML   ?

Site réalisé avec SPIP 3.2.1 + AHUNTSIC

Creative Commons License