Créer des séquences et des grilles avec R

Savoir créer des séquences de chiffres ou de chaînes de caractères sous R, ainsi que des grilles, peut être très utile.

 

J’ai régulièrement besoin de créer des séquences, pour :

  • construire un jeu de données,
  • créer les breaks sur les axes d’un plot avec ggplot2,
  • produire un clée primaire en combinant deux variables pour une jointure de deux tables.

Et j’utilise fréquemment les grilles pour réaliser des simulations de puissance :

Pour créer ces séquences et ces grilles, j’utilise les fonctions :

  •  seq()
  • rep()
  • interaction()
  • gl()
  •  expand.grid()

J’ai toujours eu du mal, à retenir comment fonctionnent certaines de ces fonctions. Cet article m’est donc utile, à moi aussi, il me servira d’aide-mémoire !

Des séquences de nombres

Pour cela, nous pouvons utiliser la fonction `seq()` qui comporte plusieurs arguments :

  • from : le point de départ
  • to : le point d’arrivée
  • by : la valeur du pas
  • length.out : la longueur souhaitée de la séquence
  • along.width : permet de récupérer une longueur souhaitée à partir d’un objet.

Les arguments from et to sont toujours nécessaires, alors que les arguments by, length.out, along.width dépendent des situations.

Voici quelques exemples :

seq(from=1, to=50, by=1)

##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## [26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

seq(from=1, to=50, by=10)

## [1]  1 11 21 31 41

seq(from=1, to=50, length.out=20)

##  [1]  1.000000  3.578947  6.157895  8.736842 11.315789 13.894737 16.473684
##  [8] 19.052632 21.631579 24.210526 26.789474 29.368421 31.947368 34.526316
## [15] 37.105263 39.684211 42.263158 44.842105 47.421053 50.000000

a <- vector(length=20)
seq(from=1, to=50,along.with=a)

##  [1]  1.000000  3.578947  6.157895  8.736842 11.315789 13.894737 16.473684
##  [8] 19.052632 21.631579 24.210526 26.789474 29.368421 31.947368 34.526316
## [15] 37.105263 39.684211 42.263158 44.842105 47.421053 50.000000
 

Des séquences répétées

Pour créer des séquences contenant des répétitions d’éléments, nous pouvons employer la fonction `rep()`. Ces fonctions comportent également plusieurs arguments :

  • x, l’élément ou le vecteur d’éléments à répéter
  • times le nombre de fois que l’élément x doit être répété
  • length.out : la taille souhaitée de la séquence à créer
  • each : le nombre de fois que doit être répété un élément du vecteur x, avant de passer au suivant

Là encore, l’argument x est toujours nécessaire, et les arguments times length.out, each sont interchangeables, et à utiliser selon ce que nous souhaitons réaliser.
Voici quelques exemples :

rep(3,times=4)

## [1] 3 3 3 3

rep("a",times=5)

## [1] "a" "a" "a" "a" "a"

rep(c(0,1), times=3)

## [1] 0 1 0 1 0 1

rep(c(0,1), length.out=8)

## [1] 0 1 0 1 0 1 0 1

rep(c("a", "b"),times=3)

## [1] "a" "b" "a" "b" "a" "b"

rep(c("a", "b"),each=3)

## [1] "a" "a" "a" "b" "b" "b"

rep(c("a", "b"),length.out=10)

##  [1] "a" "b" "a" "b" "a" "b" "a" "b" "a" "b"

rep(c("a", "b"),each=3,length.out=10)

##  [1] "a" "a" "a" "b" "b" "b" "a" "a" "a" "b"

rep(c(1:4),each=3)

##  [1] 1 1 1 2 2 2 3 3 3 4 4  

Des séquences de facteurs

La fonction gl() est assez similaire à la fonction rep, mais elle permet en plus de transformer la séquence en facteur (factor class), et même de donner un ordre dans les modalités (levels).

Cette fonction comporte plusieurs arguments :

  • n : le nombre de modalités ( ou levels) que le facteur va comporter
  • k : le nombre de réplication souhaitée
  • length : la longueur souhaitée de la séquence créée
  • labels : les étiquettes des catégories
  • ordered: permet de donner un ordre aux modalités (levels)

Voici quelques exemples :

gl(n=2, k=4, labels = c("TrtA", "TrtB"))

## [1] TrtA TrtA TrtA TrtA TrtB TrtB TrtB TrtB
## Levels: TrtA TrtB

gl(n=2,k=5, length=30, labels = c("TrtA", "TrtB"))

##  [1] TrtA TrtA TrtA TrtA TrtA TrtB TrtB TrtB TrtB TrtB TrtA TrtA TrtA TrtA TrtA
## [16] TrtB TrtB TrtB TrtB TrtB TrtA TrtA TrtA TrtA TrtA TrtB TrtB TrtB TrtB TrtB
## Levels: TrtA TrtB

gl(n=2,k=5, length=20, labels = c("TrtA", "TrtB"), ordered=TRUE)

##  [1] TrtA TrtA TrtA TrtA TrtA TrtB TrtB TrtB TrtB TrtB TrtA TrtA TrtA TrtA TrtA
## [16] TrtB TrtB TrtB TrtB TrtB
## Levels: TrtA < TrtB 

Lorsque l’argument ordered=TRUE est ajouté, nous pouvons voir dans la sortie précédente que l’ordre des modalités est TrtA < TrtB. Si nous faisons ensuite un test statistique par exemple, la modalité TrtA servira de référence.

Voici encore quelques correspondances entre les fonctions gl et rep :

gl(2, 1, 20)

##  [1] 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
## Levels: 1 2

rep(c(1,2),length.out=20)

##  [1] 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2

gl(2, 2, 20)

##  [1] 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2
## Levels: 1 2


rep(c(1,2),each=2,length.out=20)

##  [1] 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2  

Combinaison de deux variables

Je peux avoir besoin de combiner deux variables en une seule dans deux situations principales :

  • pour créer une clé primaire combinée (par exemple avec le nom et le prénom) avant de réaliser une jointure de tables.

 

  • lorsque j’ai fait une ANOVA à deux facteurs, que l’interaction est significative, et que je souhaite repasser à une ANOVA à un facteur,  en combinant les niveaux des deux variables explicatives.

Voici un exemple :

trt <- rep(c("Trt_A","Trt_B"), times=5)
trt

##  [1] "Trt_A" "Trt_B" "Trt_A" "Trt_B" "Trt_A" "Trt_B" "Trt_A" "Trt_B" "Trt_A"
## [10] "Trt_B"



vit <- rep(c("avec", "sans"),each=5)
vit
##  [1] "avec" "avec" "avec" "avec" "avec" "sans" "sans" "sans" "sans" "sans"


mydf <- data.frame(trt,vit)
mydf
##      trt  vit
## 1  Trt_A avec
## 2  Trt_B avec
## 3  Trt_A avec
## 4  Trt_B avec
## 5  Trt_A avec
## 6  Trt_B sans
## 7  Trt_A sans
## 8  Trt_B sans
## 9  Trt_A sans
## 10 Trt_B sans


mydf$trt_vit <- interaction(mydf$trt, mydf$vit, sep="_X_")
mydf
##      trt  vit      trt_vit
## 1  Trt_A avec Trt_A_X_avec
## 2  Trt_B avec Trt_B_X_avec
## 3  Trt_A avec Trt_A_X_avec
## 4  Trt_B avec Trt_B_X_avec
## 5  Trt_A avec Trt_A_X_avec
## 6  Trt_B sans Trt_B_X_sans
## 7  Trt_A sans Trt_A_X_sans
## 8  Trt_B sans Trt_B_X_sans
## 9  Trt_A sans Trt_A_X_sans
## 10 Trt_B sans Trt_B_X_sans 

Création de grilles

Pour réaliser des simulations, il peut être très utile de savoir réaliser des grilles afin de créer toutes les situations possibles. Pour cela, on utilise la fonction expand.grid().

Voici un exemple :

sexe <- c("Homme", "Femme")
groupe <- c("Traitement", "Placebo")

expand.grid(SEXE=sexe, GRP=groupe)

##    SEXE        GRP
## 1 Homme Traitement
## 2 Femme Traitement
## 3 Homme    Placebo
## 4 Femme    Placebo
 

On peut alors, très facilement rajouter de nouvelles variables dans les grilles construites :

vita <- c("oui", "non")

expand.grid(SEXE=sexe, GRP=groupe,VITA=vit

##    SEXE        GRP VITA
## 1 Homme Traitement  oui
## 2 Femme Traitement  oui
## 3 Homme    Placebo  oui
## 4 Femme    Placebo  oui
## 5 Homme Traitement  non
## 6 Femme Traitement  non
## 7 Homme    Placebo  non
## 8 Femme    Placebo  non 

La réalisation de ces grilles est particulièrement utile lorsqu’on souhaite calculer la puissance qu’un test statistique peut atteindre, en fonction de différents paramètres. Pour plus de détail, consulter l’article dédié à la puissance statistique : 

Par exemple, dans le cadre d’un test de Student de comparaisons de deux moyennes, la puissance de ce test, calculé par la fonction power.t.test() dépend de :

  •  delta : la vraie différence entre les deux moyennes
  • sd l’écart type des données
  • n : le nombre de sujets par groupe.

Très généralement, nous ne connaissons pas précisément ces trois paramètres. Alors, nous pouvons faire des simulations en les faisant varier, et en les combinant

Imaginons, par exemple que :

  •  delta peut varier entre 3 et 7
  • sd peut varier entre 9 et 11
  • que le nombre de sujets peut varier entre 50 et 350
my_delta <- c(3,4, 5, 6,7)
my_sd <- c(9,10,11) 
my_n <- seq(from=50, to=350, by=50) 

Nous pouvons alors réaliser une grille avec l’ensemble des combinaisons des modalités de ces trois paramètres :

my_grille <- expand.grid(delta=my_delta, sd=my_sd,n=my_n)

my_grille
##     delta sd   n
## 1       3  9  50
## 2       4  9  50
## 3       5  9  50
## 4       6  9  50
## 5       7  9  50
## 6       3 10  50
## 7       4 10  50
## 8       5 10  50
## 9       6 10  50
## 10      7 10  50
## 11      3 11  50
## 12      4 11  50
## 13      5 11  50
## 14      6 11  50
## 15      7 11  50
## 16      3  9 100
## 17      4  9 100
## 18      5  9 100
## 19      6  9 100
## 20      7  9 100
## 21      3 10 100
## 22      4 10 100
## 23      5 10 100
## 24      6 10 100
## 25      7 10 100
## 26      3 11 100
## 27      4 11 100
## 28      5 11 100
## 29      6 11 100
## 30      7 11 100
..................
## 91      3  9 350
## 92      4  9 350
## 93      5  9 350
## 94      6  9 350
## 95      7  9 350
## 96      3 10 350
## 97      4 10 350
## 98      5 10 350
## 99      6 10 350
## 100     7 10 350
## 101     3 11 350
## 102     4 11 350
## 103     5 11 350
## 104     6 11 350
## 105     7 11 350 

La fonction crossing du package tidyr (qui appartient au super package tidyverse) permet également de construire des grilles :

library(tidyr)

my_grille2 <- crossing(delta=my_delta, sd=my_sd,n=my_n)

head(my_grille2)

## # A tibble: 6 x 3
##   delta    sd     n
##   <dbl> <dbl> <dbl>
## 1     3     9    50
## 2     3     9   100
## 3     3     9   150
## 4     3     9   200
## 5     3     9   250
## 6     3     9   300 

Dans un second temps, à l’aide d’une boucle for() par exemple, nous pouvons compléter cette grille, en ajoutant une variable qui contient le résultat du calcul de la puissance théorique selon la fonction power.t.test() , pour chacune des situations (représentée sur une ligne) :

for(i in 1:nrow(my_grille)) {
    
    Delta = my_grille$delta[i]
    Sd = my_grille$sd[i]
    N = my_grille$n[i]
    
    my_grille$power[i] <- power.t.test(
             delta = Delta, 
             sd = Sd,
             sig.level=0.05,
             n=N,
             alternative = "two.sided")$power
}
    
head(my_grille)

##   delta sd  n     power
## 1     3  9 50 0.3784221
## 2     4  9 50 0.5950072
## 3     5  9 50 0.7853812
## 4     6  9 50 0.9099633
## 5     7  9 50 0.9706572
## 6     3 10 50 0.3175171


tail(my_grille)

##     delta sd   n     power
## 100     7 10 350 1.0000000
## 101     3 11 350 0.9497993
## 102     4 11 350 0.9977715
## 103     5 11 350 0.9999738
## 104     6 11 350 0.9999999
## 105     7 11 350 1.0000000 

Enfin, une fois les calculs réalisés, nous pouvons utiliser cette grille pour représenter les résultats , à l’aide du package ggplot2.

library(tidyverse)
library(ggplot2)

# passage en facteur des niveau de sd pour les besoins du graph
my_grille <- my_grille %>% 
    mutate(sd=as.factor(sd),
           sd=dplyr::recode(sd,"9" = "sd = 9",
                       "10" = "sd = 10",
                       "11" = "sd = 11"))

library(ggplot2)
ggplot(my_grille,aes(y=power, x=n,colour=factor(delta)))+
    geom_point()+
    geom_line()+
    scale_y_continuous(limits=c(0,1), breaks=c(0,0.25,0.5,0.6,0.7,0.8,0.9,1))+
    scale_x_continuous(limits=c(0,400), breaks=seq(from=50, to=350, by=50))+
    xlab("Nombre de sujets")+
    geom_hline(yintercept=0.8, col="black", linetype="dashed")+
    facet_wrap(~sd)+
    scale_colour_discrete(name="delta") +
    theme(axis.text.x=element_text(angle=30, hjust=1, vjust=1))+
    ggtitle("Mes simulations de puissance") 
grille et calcul de puissance

Remarque : Les breaks sur l’axe des x sont construits grâce à la fonction seq().

Les grilles peuvent aussi être employées pour réaliser des prédictions, à partir d’un modèle linéaire, par exemple. Pour plus d’informations, cliquez ici !

 

Et vous, est-ce-que vous connaissez d’autres fonctions pour créer des séquences ? Si oui, partagez les en commentaire !

Si cet article vous a plu, ou vous a été utile, et si vous le souhaitez, vous pouvez soutenir ce blog en faisant un don sur sa page Tipeee 🙏

Image par Gerd Altmann de Pixabay 

5 Responses

  1. Y a moyen de créer un vecteur tout en combinant les fonctions rep et seq et avec des éléments repris 2 fois et ensuite 3 fois et 4 fois ?

    Merci de bien vouloir répondre !
    Salut !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Aide mémoire off'R ;)

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.