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”
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 ...
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
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ée 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
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
Je me sers souvent de la fonction ifelse()
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 ifelse()
, 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
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 setosa
et virginica
et que je consulte les niveaux de la variable Species
, alors les 3 niveaux d’origine vont être affichés : setosa
, virginica
, 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()
peut être employée pour recoder les niveaux d’une variable catégorielle. Par exemple, si je souhaite recoder :
iris5 <- iris %>%
mutate(Species=recode(Species,
setosa="set",
virginica="virgi",
versicolor="versi"))
levels(iris5$Species)
## [1] "set" "versi" "virgi"
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"
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.
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.
13 Responses
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)
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
Bonjour Xavier,
je ne connaissais pas du tout cette fonction, merci pour ce partage !
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 🙂
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
Genial
Peut etre juste expliquer mutate
Bonjour Christelle,
Merci pour votre suggestion.
Alors pour la fonction mutate() , je renvoie à la partie 5 de cet article : https://statistique-et-logiciel-r.com/initiation-a-la-manipulation-de-donnees-avec-le-package-dplyr/
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!
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
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()
Merci !
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.
C’était un erreur, j’utilise la fonction ifesle() et pas if_else(), bien qu’elle puisse aussi être utilisée 😉