On en entend de plus en plus parler, son utilisation devient la norme quand on code en R, et quand on met le nez dedans, on ne peut plus s’en passer ! Que ce soit pour importer, mettre en forme, manipuler, visualiser ou modéliser les données, le tidyverse saura vous donner une solution élégante et répondra à (presque) tous vos besoins.
Sommaire
Introduction au tidyverse
On vous en parlait déjà en 2016 à l’occasion de son avènement, le tidyverse, qui s’appelait à l’origine le hadleyverse, n’a cessé d’évoluer depuis !
Alors ok, on peut faire tout un tas de choses grâce au tidyverse, mais de quoi on parle exactement ? “tidyverse”, contraction de “tidy” et de “universe”, c’est un univers bien rangé si l’on traduit mot à mot. Dans les faits, il s’agit d’un ensemble de packages R qui sont conçus pour fonctionner ensemble et suivant de ce fait une même logique de code et une grammaire commune. Aujourd’hui, ces packages sont officiellement au nombre de 26, pas moins ! Cet univers est en constante évolution, en témoignent les 36 repositories Git, alimentés par 21 contributeurs majeurs dont le fameux Hadley Wickham qui est à l’origine de cet ambitieux projet.
Installation et chargement
L’installation de l’ensemble des packages du tidyverse se fait via la ligne de commande suivante :
install.packages("tidyverse")
Par ailleurs, lorsque l’on charge le tidyverse via :
library(tidyverse)
les packages du tidyverse les plus communément utilisés sont chargés dans votre session :
{ggplot2}
{dplyr}
{tidyr}
{readr}
{purrr}
{tibble}
{stringr}
{forcats}
Les autres packages seront à charger de manière indépendante en fonction de vos besoins. Pour avoir la liste exhaustive des packages du tidyverse :
tidyverse::tidyverse_packages()
## [1] "broom" "cli" "crayon" "dbplyr" "dplyr" "forcats" "ggplot2"
## [15] "pillar" "purrr" "readr" "readxl" "reprex" "rlang" "rstudioapi"
## [22] "rvest" "stringr" "tibble" "tidyr" "xml2" "tidyverse"
Note : certains packages, comme par exemple
{glue}
qui nous propose une alternative à la fonctionpaste()
, ne sont pas encore dans cette liste, et ne sont pas installés avec les autres packages du tidyverse, mais ils sont tout de même considérés comme en faisant partie.
{magrittr}
ou le règne du pipe
Le pipe, ou %>%
, c’est l’un des éléments centraux du tidyverse. Il permet de structurer des séquences d’opérations en minimisant la création d’objets intermédiaires et en facilitant l’ajout d’une étape n’importe où dans cette séquence. Il est utilisé PARTOUT dans le tidyverse, à tel point que la fonction %>%
est exportée par tous ces packages, d’où le fait que {magrittr}
ne soit pas automatiquement chargé avec les autres packages principaux.
Bon du coup, comment on l’utilise, ce fameux pipe ? Déjà, on le lit de gauche à droite : “fais ça, et puis ça, et ensuite ça, …”. Autrement dit : x %>% f()
sera équivalent à f(x)
, et de la même manière, x %>% f() %>% g()
sera équivalent à g(f(x))
. Bien plus lisible avec le pipe non ? un exemple un peu plus complet :
library(magrittr)
# le chargement de magrittr n'est pas utile ici si on a déjà chargé un autre package du tidyverse
iris %>%
arrange(Sepal.Length) %>%
filter(Petal.Length > 5) %>%
head(5) %>%
write_csv2("mon_iris.csv")
En ‘pseudo code’ le %>%
permet d’écrire ce genre de choses :
moi %>%
je_me_leve(horaire = "8h00") %>%
je_m_habille(haut = "chemise", bas = "jeans") %>%
prend_le_petit_dej()
ce qui est toujours plus lisible que :
prend_le_petit_dej(je_m_habille(je_me_leve(moi, horaire = "8h00"),
haut = "chemise", bas = "jeans"))
non ?
Le
%>%
classique connait quelques variations, comme%T>%
ou%<>%
. On ne résiste pas à l’envie de vous les présenter, même si on peut vivre une vie épanouie sur R sans connaître ou utiliser ces pipes alternatifs (presque de l’ordre de la curiosité), c’est toujours intéressant pour la culture-R.
Un autre genre de pipe qui peut être intéressant et qui nous vient également de {magrittr}
, c’est le %T>%
: on l’utilise dans le cas où l’une de nos instructions ne renvoie rien, comme par exemple plot()
, mais que l’on souhaite tout de même garder un résultat intermédiaire de notre séquence d’instructions afin de lui appliquer une autre instruction. %T>%
gardera ce qu’il y a avant son appel :
iris %>%
select(Petal.Length, Petal.Width) %T>%
plot() %>%
summary()
## Petal.Length Petal.Width
## Min. :1.000 Min. :0.100
## 1st Qu.:1.600 1st Qu.:0.300
## Median :4.350 Median :1.300
## Mean :3.758 Mean :1.199
## 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :6.900 Max. :2.500
Et comme ils n’ont fait pas les choses à moitié, ce qu’on appelle le “diamond pipe” et qui est un combo pipe + assignation est matérialisé dans {magrittr}
par %<>%
. Comment ça marche ? C’est très simple : au lieu d’écrire :
iris <- iris %>%
filter(Petal.Length > mean(Petal.Length))
On écrira :
iris %<>%
filter(Petal.Length > mean(Petal.Length))
Pretty cool non ?! (Bon en vrai, en termes de bonnes pratiques, c’est pas génial, mais c’est cool 🙂 )
Et enfin, si vous avez besoin d’utiliser une fonction à laquelle on ne peut passer en paramètre que des vecteurs dans votre série d’instructions, vous pourrez toujours utiliser le pipe %$%
. Petite démo :
iris %$%
cor(Sepal.Length, Sepal.Width)
## [1] 0.3315529
On évite ainsi l’erreur suivante :
iris %>%
cor(Sepal.Length, Sepal.Width)
Note : seul le pipe
%>%
est exporté par les autres packages du tidyverse, pour les autres, il faudra explicitement charger{magrittr}
vialibrary(magrittr)
.
L’import des données
De nombreux packages du tidyverse sont dédiés à la lecture et à l’écriture des données depuis R ; à chaque package correspond un type particulier de données, ces dernières étant importées sous forme de tibbles.
Le package {readr}
Il permet d’importer et écrire une large gamme de fichiers plats :
Lecture | Ecriture | |
---|---|---|
read_lines() |
write_lines() |
|
read_file() |
write_file() |
|
les fichiers plats en général, ayant un séparateur | read_delim() |
write_delim() |
les csv | read_csv() (séparateur , ) et read_csv2() (séparateur ; ) |
write_csv() et read_csv2() |
les fichiers avec un séparateur Tab | read_tsv() |
write_tsv() |
les fichiers avec un séparateur Espace, simple, double, ou plus | read_table() et read_table2() |
|
les fichiers log | read_log() |
|
es fichiers à largeur fixe (toutes les lignes ont le même nombre de caractères) | read_fwf() |
La cheat sheet de {readr}
c’est ici !
Le package {readxl}
Il est propre à l’import de fichiers Excel :
read_xls()
pour les fichiers .xlsread_xlsx()
pour les fichiers .xlsxread_excel()
pour les deux types de fichiers
Le package {xml2}
Il permet de parser, télécharger et écrire :
- des fichiers XML, via les fonctions
read_xml()
,download_xml()
,write_xml()
- des fichiers HTML, via les fonctions
read_html()
,downlad_html()
,write_html()
Le package {httr}
Il s’agit d’une surcouche du package {curl}
, permettant de requêter des APIs grâce aux fonctions GET()
, HEAD()
, PATCH()
, PUT()
, DELETE()
et POST()
.
Le package {jsonlite}
Il est spécifique à la lecture et à l’écriture de fichiers JSON, ainsi qu’à la conversion vers et depuis R :
parse_json()
,read_json()
etfromJSON()
: JSON -> Rwrite_json()
ettoJSON()
: R -> JSON
Le package {haven}
Surcouche du package écrit en C ReadStat, {haven}
permet l’import de données issues d’autres langages/logiciels statistiques :
- SAS : la fonction
read_sas()
importe les données depuis des fichiers .sas7bdat et .sas7bcat, etread_xpt()
les fichiers .xpt (SAS transport files) - SPSS : les fonctions
read_sav()
etwrite_sav()
permettent, comme leur nom l’indique, la lecture et l’écriture de fichiers .sav, et la fonctionread_por()
lis les anciens fichiers .por - Stata : les fonctions
read_dta()
etwrite_dta()
permetten quant à elles la lecture et l’écriture des fichiers .dta
Le package {rvest}
Nous vous en avions déjà parlé en 2017, en long, en large et en travers. C’est LE package pour faire du webscraping.
Après avoir importé vos données avec la fonction read_html()
de {xml2}
, les fonctions de {rvest}
vous permettront d’accéder aux différentes parties du document HTML via
- les selecteurs CSS grâce à la fonction
html_nodes()
- les noms de tags html grâce à la fonction
html_name()
html_text()
donne accès au texte, html_attr()
au contenu d’un attribut, et html_attrs()
à tous les attributs.
Il en est de même pour les fichiers parsés avec read_xml()
, sur lesquels on pourra appeler les fonctions similaires aux précédentes : xml_nodes()
, xml_name()
, xml_attr()
et xml_attrs()
.
Vous pourrez également :
- parser des tables en data frames avec
html_table()
- extraire, modifier et soumettre des formulaires avec
html_form()
,set_values()
etsubmit_form()
- détecter et corriger des problèmes d’encoding avec
guess_encoding()
etrepair_encoding()
- naviguer sur une page web avec
html_session()
,jump_to()
,follow_link()
,back()
ou encoreforward()
La mise en forme et la manipulation des données
Maintenant que nous avons tous les outils pour importer nos données, sous quelque format dans lequel elles sont enregistrées, nous allons pouvoir les manipuler, les mettre en forme, les tordre dans tous les sens.
Le package {tibble}
Je vous disais plus haut que les données importées via les différents packages du tidyverse étaient de la classe tibble
notée tbl_df
. Mais c’est quoi un tibble au juste ? C’est la version moderne du data.frame, à quelques différences près :
- les colonnes ne sont pas renommées automatiquement (si vous avez des espaces dans les noms de vos colonnes par exemple, ils ne seront pas remplacés par des points). Mais les colonnes ayant un nom identique seront suffixées pour les rendre uniques.
- les types des variables ne seront pas modifiés : finito les
stringsAsFactor = FALSE
que l’on devait se coltiner (sur R < 4.0) à chaque import de données contenant des chaînes de caractères ! - les tibbles disposent également de leur propre version de
print()
permettant un affichage beaucoup plus agréable à lire mais aussi plus complet. Seules les premières lignes sont affichés, mais on a par ailleurs la classe associée à chaque colonne, sous le nom de cette dernière. Par exemple, avec les donnéesiris
:
iris %>% as_tibble()
## # A tibble: 42 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 6 2.7 5.1 1.6 versicolor
## 2 6.3 3.3 6 2.5 virginica
## 3 5.8 2.7 5.1 1.9 virginica
## 4 7.1 3 5.9 2.1 virginica
## 5 6.3 2.9 5.6 1.8 virginica
## 6 6.5 3 5.8 2.2 virginica
## 7 7.6 3 6.6 2.1 virginica
## 8 7.3 2.9 6.3 1.8 virginica
## 9 6.7 2.5 5.8 1.8 virginica
## 10 7.2 3.6 6.1 2.5 virginica
## # ... with 32 more rows
Le passage de data.frame
à tibble
et inversement se fait simplement via les fonctions as_tibble()
de {tibble}
et as.data.frame()
de R {base}
.
Avec cette nouvelle classe, de nouvelles manières de subsetter les éléments, mais comme les tibbles
sont également des data.frames
, les fonctions old school seront toujours valides :
iris_tbl <- iris %>% as_tibble()
# extraction de la 2eme colonne de iris par son nom
iris_tbl$Sepal.Length
iris_tbl %>% .$Sepal.Length # version tidy
# ou bien
iris_tbl[["Sepal.Length"]]
iris_tbl %>% .[["Sepal.Length"]] # version tidy
# extraction de la 2eme colonne de iris par son indice
iris_tbl[[2]]
iris_tbl %>% .[[2]] # version tidy
Et pour créer des tibbles from scratch, deux fonctions du package {tibble}
:
tibble()
pour créer des tibbles par colonne, de la même manière que l’on crée des data.frames :
tibble(
v1 = rnorm(10),
v2 = letters[1:10],
v3 = as.Date("2020-01-01") + 0:9
)
## # A tibble: 10 x 3
## v1 v2 v3
## 1 -0.646 a 2020-01-01
## 2 -1.52 b 2020-01-02
## 3 -0.144 c 2020-01-03
## 4 -0.656 d 2020-01-04
## 5 0.364 e 2020-01-05
## 6 2.18 f 2020-01-06
## 7 0.322 g 2020-01-07
## 8 -0.750 h 2020-01-08
## 9 -0.760 i 2020-01-09
## 10 -0.310 j 2020-01-10
tribble()
pour créer des tibbles par ligne, les noms de colonnes sont indiqués via des~
:
tribble(
~colonne1, ~colonne2, ~colonne3,
1, "a", as.Date("2020-01-01"),
4, "b", as.Date("2020-01-02"),
7, "c", as.Date("2020-01-03")
)
## # A tibble: 3 x 3
## colonne1 colonne2 colonne3
## 1 1 a 2020-01-01
## 2 4 b 2020-01-02
## 3 7 c 2020-01-03
Pour en savoir plus sur les tibbles, vous pouvez lire le chapitre dédié aux tibbles du Livre R for Datascience.
Mettre en forme ses données avec la package {tidyr}
{tidyr}
, c’est LE package pour retourner ses données dans tous les sens, grâce à ses fonctions pivot_longer()
et pivot_wider()
. Je vous en avais déjà parlé à l’occasion de l’article Tout ce que vous voulez savoir sur le pivot, allez y faire un petit tour pour savoir ce que sont des données tidy et comment les obtenir en devenant un as du pivoting !
Mais dans ce package il y a aussi tout un tas de petites fonctions bien sympathiques, comme par exemple :
expand()
,expand_grid()
,crossing()
,complete()
etnesting()
qui permettent de créer des combinaisons de listes ou de vecteursdrop_na()
qui supprime les lignes contenant des NAseparate()
,extract()
qui permettent de splitter une colonne de classechar
en plusieurs colonnes et permettant d’utiliser des expressions régulières- ou au contraire
unite()
pour joindre des colonnes.
Manipuler ses données avec le package {dplyr}
Alors {dplyr}
, c’est un peu la base du {tidyverse}
. Ce package nous permet un grand nombre d’opérations indispensables à l’exploration, la manipulation et les
calculs sur les données :
mutate()
pour ajouter des nouvelles variables/colonnes, ou modifier les existantes, en fonction ou non pas autres variables de la tableselect()
pour sélectionner des variables/colonnes par leur nomfilter()
pour séletionner des lignes conditionnellement aux valeurs d’une ou plusieurs colonnessummarise()
pour résumer les lignesarrange()
pour ordonner les lignes- et bien d’autres…
Et pour un peu de pratique en live, je vous propose la vidéo du Meetup Raddict dans laquelle Romain François nous parle de quelques fonctions majeures de {dplyr}
.
La cheat sheet de {dplyr}
c’est ici!
Manipuler les chaînes de caractères avec {stringr}
{stringr}
nous vient avec une pléthore de fonctions str_()
nous permettant une manipulation facilitée des chaînes de caractères :
- pour détecter des patterns, avec
str_detect()
,str_which()
,str_count()
etstr_locate()
- pour extraire des patterns, avec
str_sub()
,str_subset()
,str_extract()
etstr_match()
- pour gérer les longueurs de chaînes, avec
str_length()
,str_pad()
,str_trunc()
etstr_trim()
- pour modifier les chaînes de caractères avec
str_sub()
,str_replace()
,str_to_lower()
,str_to_upper()
etstr_to_title()
- pour concaténer et splitter avec
str_c()
,str_dup()
,str_split_fixed()
,str_glue()
etstr_glue_data()
Vous aurez également besoin dans certains cas de maitriser les expressions régulières, et pour cela de lire notre article sur les expressions régulières.
La cheat sheet de {stringr}
c’est ici!
- déterminer le type de jour (semaine, weekend ?), année (bissextile ?), heure (matin, après-midi, jour, nuit ?), …
- gérer les différentes timezones
- …
Il y a tellement de fonctions que c’est compliqué de tout décrire ici, mais la cheat sheet est vraiment bien faite :
Le package {hms}
permet quant à lui de manipuler les heures – minutes – secondes avec une classe dédiée : hms
. Par exemple :
hms::hms(56, 34, 12)
## 12:34:56
Et là attention, deux choses :
- l’ordre des paramètres, contrairement à ce que pourrait nous faire penser le nom de la fonction, n’est pas heure, minute, seconde, mais seconde, minute, heure. Oui je sais, mais c’est comme ça.
Manipuler les facteurs avec {forcats}
La cheat sheet de {forcats}
c’est ici!
Itérer grâce à {purrr}
C’est encore une fois un package dont on vous a déjà parlé plusieurs fois :
Avec les fonctions map_()
et accumulate()
, vous n’aurez plus aucune boucle for
dans vos codes !
La cheat sheet de {purrr}
c’est ici!
tidy-modéliser avec {modelr}
?
{modelr}
, je vous le dis tout de suite, c’est déjà dépassé. En effet, pas de nouveautés sur le repo Git du package depuis 6 mois. Alors on fait quoi quand on souhaite faire nos modèles tout en conservant notre tidy-grammaire ? C’est simple : on se tourne vers les tidymodels
! Les packages du tidymodels ne faisant pas partie du tidyverse, je ne m’étendrai pas dessus dans cet article, mais je vous invite à aller voir de plus près la page des tidymodels, vous y trouverez des informations sur les packages qui le composent.
Et les autres packages du tidyverse :
- se connecter à une base de données avec
{dbplyr}
: https://db.rstudio.com/dplyr/ - visualiser les données avec l’incontournable
{ggplot2}
: La cheat sheet de{ggplot2}
c’est ici! - demander de l’aide efficacement avec
{reprex}
La tidy évaluation avec {rlang}
Nous vous parlerons bientôt dans un nouvel article de ce package et des nouveautés côté tidy évaluation, car les choses ont pas mal évolué depuis notre aticle sur la tidyeval ! Les doubles moustaches n’auront bientôt plus de secrets pour vous, patience !
En attendant, la cheat sheet de {rlang}
c’est ici!
Pour aller plus loin
Ils sont prolifiques chez RStudio vous ne trouvez pas ? Afin de suivre les évolutions nombreuses et fréquentes du tidyverse, je vous invite à jeter un oeil régulièrement au blog du tidyverse qui regorge d’informations, d’articles, de news, …
Si un package en particulier vous intéresse et que vous souhaitez que nous en parlions plus en détail, faites-le nous savoir !
Laisser un commentaire