C'est de la data et mon expeRtise afin d'en tirer le maximum

8 fonctions pour la manipulation

Dans cet article, je vous présente, 8 fonctions très utiles, que j’utilise quasi quotidiennement pour analyser des données, et qui sont parfois méconnues !
Cet article est complémentaire à celui dédié à la manipulation de données avec le package dplyr.

Certaines des fonctions décrites ici appartiennent également à ce package dplyr. Ce package rentre parfois en conflit avec d’autres packages déjà installés. Pour solutionner ces situations, je vous recommande de lire l’article “Un petit hack pour éviter les conflits de packages sous R”

Table des matières

La fonction pull()

La fonction pull appartient au package dplyr qui lui-même appartient au super package tidyverse. Elle permet d’extraire directement une colonne d’un data frame, sous la forme d’un vecteur.

Cette fonction est l’équivalent du $ dans la commande mydata$colonne, mais elle a l’avantage d’être tidyverse compatible, et donc de pouvoir s’intégrer à une suite d’instructions.

Dans l’exemple ci-dessous, je filtre les données de l’espèce setosa, puis je calcule la surface des sépales, et j’extrais cette variable, grâce à la fonction pull(), pour la stocker dans un vecteur :

#install.packages("tidyverse") 
library(tidyverse)

area<- iris %>%
    filter(Species=="setosa") %>% 
    mutate(area=Sepal.Length*Sepal.Width) %>% 
    pull(area)

is.vector(area)
str(area)
##  num [1:50] 17.8 14.7 15 14.3 18 ...

is.vector(area)
## [1] TRUE 

Alors que si vous utilisez select() vous allez extraire un data.frame, et pas un vecteur ! Cela est moins pratique, car il faudra une seconde étape pour extraire uniquement la colonne d’intérêt.

area <- iris %>%
    filter(Species=="setosa") %>% 
    mutate(area=Sepal.Length*Sepal.Width) %>% 
    select(area)

str(area)
## 'data.frame':    50 obs. of  1 variable:
##  $ area: num  17.8 14.7 15 14.3 18 ... 

La fonction slice()

Cette fonction permet de filtrer des lignes, en fonction de leurs indices. Elle appartient également au package dplyr, elle peut donc s’intégrer à l’intérieur d’une suite de commandes, avec l’utilisation du pipe %>%.

En reprenant une partie de l’exemple précédent, je vais arranger les lignes dans l’ordre décroissant des surface de sépales , et ne conserver que les 5 plus grandes :

area_top5 <- iris %>%
    filter(Species=="setosa") %>% 
    mutate(area=Sepal.Length*Sepal.Width) %>% 
    arrange(desc(area)) %>% 
    slice(1:5)

area_top5
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  area
## 1          5.7         4.4          1.5         0.4  setosa 25.08
## 2          5.8         4.0          1.2         0.2  setosa 23.20
## 3          5.5         4.2          1.4         0.2  setosa 23.10
## 4          5.7         3.8          1.7         0.3  setosa 21.66
## 5          5.2         4.1          1.5         0.1  setosa 21.32

 

La fonction slice() permet également filtrer des lignes discontinues. Dans l’exemple ci-dessous, les lignes 1, 50 et 100 :

iris  %>% 
    slice(c(1,50, 100))

##   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
## 1          5.1         3.5          1.4         0.2     setosa
## 2          5.0         3.3          1.4         0.2     setosa
## 3          5.7         2.8          4.1         1.3 versicolor     

La fonction slice() possède quelques variantes, comme :

  • slice_head() qui permet d’extraire les premières lignes,
  • slice_tail() qui permet d’extraire les dernières lignes,
  • slice_min() qui permet d’extraire la ligne de la plus faible valeur d’une variable donnée,
  • slice_max()qui permet d’extraire la ligne de la plus forte valeur d’une variable donnée,
  • slice_sample() qui permet d’extraire un échantillon de lignes au hasard 
iris  %>% 
    slice_sample(n=5, replace=FALSE)
    
##   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
## 1          5.4         3.0          4.5         1.5 versicolor
## 2          4.4         2.9          1.4         0.2     setosa
## 3          6.8         2.8          4.8         1.4 versicolor
## 4          7.7         3.8          6.7         2.2  virginica
## 5          4.4         3.2          1.3         0.2     setosa     

La fonction relocate()

Cette fonction permet de modifier l’ordre des colonnes d’un data frame. Elle appartient également au package dplyr.

Dans l’exemple ci-dessous, je créais un second jeu de données iris (appelé iris2) en recopiant iris, mais en positionnant la colonne Species en première position :

iris2 <-iris %>% 
    relocate(Species, everything())

head(iris2)
##   Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1  setosa          5.1         3.5          1.4         0.2
## 2  setosa          4.9         3.0          1.4         0.2
## 3  setosa          4.7         3.2          1.3         0.2
## 4  setosa          4.6         3.1          1.5         0.2
## 5  setosa          5.0         3.6          1.4         0.2
## 6  setosa          5.4         3.9          1.7         0.4 

La fonction everything() permet de dire “et ensuite toutes les autres variables”.

Remarque : cette modification de l’ordre des variables est aussi possible avec la fonction select(), mais la fonction relocate() offre plus de possibilités. Par exemple, ici de positionner Species après la variable Sepal.Width, grâce à l’argument .after :

iris3 <-iris %>% 
    relocate(Species, .after=Sepal.Width)
head(iris3)
##   Sepal.Length Sepal.Width Species Petal.Length Petal.Width
## 1          5.1         3.5  setosa          1.4         0.2
## 2          4.9         3.0  setosa          1.4         0.2
## 3          4.7         3.2  setosa          1.3         0.2
## 4          4.6         3.1  setosa          1.5         0.2
## 5          5.0         3.6  setosa          1.4         0.2
## 6          5.4         3.9  setosa          1.7         0.4 

Pour plus de détails, consulter l’aide :

?relocate 

La fonction count()

Cette fonction appartient toujours au package dplyr, elle permet d’obtenir le nombre de lignes correspondant à une situation. Comme elle est tidyverse compatible, elle est très utile en combinaison avec la fonction group_by()

Par exemple, si je veux connaitre, dans le jeu de données heart_disease (du package funModelling), combien de lignes correspondent aux croisement des modalité has_heart_disease et gender :

library(funModeling)

heart_disease %>% 
    group_by(has_heart_disease, gender) %>% 
    count()
    
## # A tibble: 4 x 3
## # Groups:   has_heart_disease, gender [4]
##   has_heart_disease gender     n
##   <fct>             <fct>  <int>
## 1 no                female    72
## 2 no                male      92
## 3 yes               female    25
## 4 yes               male     114     

La fonction if_else()

Je me sers souvent de la fonction if_else() pour créer une variable catégorielle à partir d’une variable numérique. Dans l’exemple ci-dessous, je créais une variable grp qui prend pour valeur “low” si la longueur du pétale est inférieure à la médiane, et “high” sinon.

median(iris$Petal.Length)
## [1] 4.35

iris <- iris %>% 
    mutate(grp=ifelse(Petal.Length<=4.35, "low", "high"))

# on vérifie
iris %>% 
    slice_sample(n=10, replace=FALSE)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species  grp
## 1           5.1         3.4          1.5         0.2     setosa  low
## 2           4.9         2.5          4.5         1.7  virginica high
## 3           6.0         2.2          4.0         1.0 versicolor  low
## 4           5.0         3.2          1.2         0.2     setosa  low
## 5           6.7         3.0          5.2         2.3  virginica high
## 6           5.0         3.0          1.6         0.2     setosa  low
## 7           7.4         2.8          6.1         1.9  virginica high
## 8           6.5         3.2          5.1         2.0  virginica high
## 9           6.8         2.8          4.8         1.4 versicolor high
## 10          7.6         3.0          6.6         2.1  virginica high 

Et pour faire 3 catégories, il suffit d’emboîter deux if_else(), comme ceci :

iris <- iris %>% 
    mutate(grp=ifelse(Petal.Length<=4.35, "low", 
                      ifelse(Petal.Length<=5.1, "med", "high")))

# on vérifie
iris %>% 
    slice_sample(n=10, replace=FALSE)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species  grp
## 1           6.5         3.0          5.5         1.8  virginica high
## 2           5.1         3.5          1.4         0.2     setosa  low
## 3           4.6         3.2          1.4         0.2     setosa  low
## 4           6.7         3.1          4.7         1.5 versicolor  med
## 5           5.2         4.1          1.5         0.1     setosa  low
## 6           6.1         3.0          4.9         1.8  virginica  med
## 7           5.0         2.0          3.5         1.0 versicolor  low
## 8           5.1         3.8          1.6         0.2     setosa  low
## 9           6.1         2.8          4.7         1.2 versicolor  med
## 10          5.1         3.8          1.5         0.3     setosa  low 

La fonction droplevels()

Cette fonction permet de retirer de la mémoire de R des niveaux d’une variable catégorielle, qui ne sont plus employés. Par exemple, si je créais un sous-jeu de données ne contenant plus que les espèces setosaet virginica et que je consulte les niveaux de la variable Species, alors les 3 niveaux d’origine vont être affichés : setosavirginica, et versicolor. La fonction droplevels, permet de retirer (de la mémoire) le niveau versicolor.

# création du sous groupe de données
seto_virgi <- iris %>% 
    filter(Species %in% c("setosa", "virginica"))

# consultation des niveaux de la variable Species
levels
## [1] "setosa"     "versicolor" "virginica"

# on retire les niveaux absents
seto_virgi$Species <- droplevels(seto_virgi$Species)
# verification
levels(seto_virgi$Species)
## [1] "setosa"    "virginica" 

La fonction fct_drop() du package forcats (qui appartient au package tidyverse), permet de faire exactement la même chose, lorsqu’elle est employée dans une fonction mutate() :

seto_versi <- iris %>% 
        filter(Species %in% c("setosa", "virginica")) %>%
        mutate(Species = fct_drop(Species))
        
# verification
levels(seto_versi$Species)
## [1] "setosa"    "virginica" 

La fonction recode()

La fonction recode() peut être employée pour recoder les niveaux d’une variable catégorielle. Par exemple, si je souhaite recoder :

  • “setosa” en “seto”
  • “virginica” et “virgi”
  • “versicolor” en “versi”
iris5 <- iris %>% 
    mutate(Species=recode(Species,
                          setosa="set", 
                          virginica="virgi", 
                          versicolor="versi"))

levels(iris5$Species) 
## [1] "set"   "versi" "virgi" 

Les fonctions str_to_lower(), str_to_upper et str_to_tile

Lorsque j’importe des données et qu’il n’y a pas d’homogénéité dans le nommage des variables (certaines sont écrites en minuscule, d’autre en majuscule), j’utilise ces fonctions pour les uniformiser. Elles appartiennent au package stringr qui appartient au super package tidyverse. Voici un exemple avec le jeu de données hall.fame contenu dans le package UsingR :

library(UsingR)
names(hall.fame)
##  [1] "first"                   "last"                   
##  [3] "seasons"                 "games"                  
##  [5] "AB"                      "runs"                   
##  [7] "hits"                    "doubles"                
##  [9] "triples"                 "HR"                     
## [11] "RBI"                     "BB"                     
## [13] "SO"                      "BA"                     
## [15] "OBP"                     "SP"                     
## [17] "AP"                      "BR"                     
## [19] "ABRuns"                  "Runs.Created"           
## [21] "SB"                      "CS"                     
## [23] "Stolen.Base.Runs"        "Fielding.Average"       
## [25] "Fielding.Runs"           "Primary.Position.Played"
## [27] "Total.Player.Rating"     "Hall.Fame.Membership" 

Nous pouvons voir que certains noms sont en majuscule, d’autres en minuscule, et d’autres encore comportent une majuscule sur la première lettre. Dans un premier temps, nous pouvons passer tous les noms en minuscule :

names(hall.fame) <- str_to_lower(names(hall.fame))
# verification
names(hall.fame)
##  [1] "first"                   "last"                   
##  [3] "seasons"                 "games"                  
##  [5] "ab"                      "runs"                   
##  [7] "hits"                    "doubles"                
##  [9] "triples"                 "hr"                     
## [11] "rbi"                     "bb"                     
## [13] "so"                      "ba"                     
## [15] "obp"                     "sp"                     
## [17] "ap"                      "br"                     
## [19] "abruns"                  "runs.created"           
## [21] "sb"                      "cs"                     
## [23] "stolen.base.runs"        "fielding.average"       
## [25] "fielding.runs"           "primary.position.played"
## [27] "total.player.rating"     "hall.fame.membership" 

Nous pouvons ensuite, dans un second temps, ajouter une Majuscule à la première lettre :

names(hall.fame) <- str_to_title(names(hall.fame))
# verification
names(hall.fame)
##  [1] "First"                   "Last"                   
##  [3] "Seasons"                 "Games"                  
##  [5] "Ab"                      "Runs"                   
##  [7] "Hits"                    "Doubles"                
##  [9] "Triples"                 "Hr"                     
## [11] "Rbi"                     "Bb"                     
## [13] "So"                      "Ba"                     
## [15] "Obp"                     "Sp"                     
## [17] "Ap"                      "Br"                     
## [19] "Abruns"                  "Runs.created"           
## [21] "Sb"                      "Cs"                     
## [23] "Stolen.base.runs"        "Fielding.average"       
## [25] "Fielding.runs"           "Primary.position.played"
## [27] "Total.player.rating"     "Hall.fame.membership" 

Conclusion

J’espère vous avoir fait découvrir au moins une nouvelle fonction parmi ces 8 fonctions décrites !

Et vous, est ce que vous avez une super fonction, qui vous utilisez très souvent, et qui est méconnue ? Si oui, s’il vous plait, partagez là en commentaire !

Merci !

En attendant, si cet article vous a plu ou vous a été utile, n’oubliez pas de le partager ! Vous pouvez également soutenir le blog par un don libre sur la page Tipeee.

12 réponses

  1. bonjour,
    merci pour vos articles toujours intéressants et agréable à lire
    une fonction que je trouve bien pratique est clean_names() du package janitor qui permet d’hamoniser facilement les noms de colonnes ( par ex en supprimant les accents , les espaces..) lors d’import de fichier de données

    ex:
    library (janitor)

    df % clean_names(“snake”)
    df

    A tibble: 1 x 1

    elongation_du_parametre

    1 1

    il existe d’autres valeurs de paramètre autre que “snake” il suffit de regarder l’aide
    bonne journée

  2. Merci pour ces astuces !

    Pour ma part, j’ai découvert il n’y a pas si longtemps les packages questionr et esquisse … Je les partage toujours aux stagiaires et aux collègues qui ne sont pas des grands adeptes de R et c’est le succès à tous les coups 🙂

    1. Bonjour,

      Moi aussi j’ai découvert questionnr il y a peu, et c’est vrai qu’il est utile. J’en ferai peut être un sujet d’article…
      Bonne continuation

  3. Bonjour, merci pour ces infos super pratiques. J’avoue que je n’utilise pas les fonctions slice() et relocate(). J’aime beaucoup la fonction case_when() pour recoder des variables en facteurs car je la trouve plus facile à expliciter que des multiples if_else lorsque j’ai plusieurs catégories.
    Super info pour les fonctions de stringr auxquelles je pense trop peu.
    Toujours pratico-pratique ces conseils sont supers!

  4. BRAVO, c’est limpide, et tellement utile ! On peut ressortir les fiches le jour où on utilise R, car c’est une des difficultés de l’utilisateur lambda : R est nécessaire pour traiter une question,puis on peut ne pas l’utiliser pendant des semaines. Savoir qu’il existe cette reference est d’une grande aide

  5. Merci pour cet article ! (et ce blog d’une manière générale)

    Je me permets de suggérer 2 variantes :

    5 : dplyr::case_when

    iris %<>% mutate(grp = case_when(Petal.Length <= 4.35 ~ “low”,
    Petal.Length > 5.1 ~ “high”,
    TRUE ~ “med”))

    6 : Je trouve que c’est encore plus lisible en utilisant le %<>% de magrittr

    seto_virgi$Species %<>% droplevels()

  6. Merci, super article qui donne envie de se convertir au tidyverse.
    Juste : au § La fonction if_else(), est-ce la fonction if_else() du package dyplr qui est utilisée
    ou bien la classique ifelse() du package base ?
    Merci
    E.

Laisser un commentaire

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

Bonjour !

vous venez souvent ?

Identifiez-vous pour avoir accès à toutes les fontionnalités !

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.