library(dplyr)
library(microbenchmark)
Le chaînage d’opérations est disponible depuis plusieurs années via
le pipe %>%
de {{maggritr}}
(exporté dans
et utilisé via {{dplyr}}
). R 4.1.+ a introduit un opérateur
de pipe natif |>
.
Cet opérateur séquentiel fonctionne de la même manière que le
%>%
usuel.
10:15 %>% # Pour le vecteur 10:15
sqrt() %>% # On prend la racine carrée, puis
mean() %>% # On calcule la moyenne
round(digits = 2) # On arrondit
## [1] 3.53
# Maintenant, avec le pipe "natif"
10:15 |> # Pour le vecteur 10:15
sqrt() |> # On prend la racine carrée, puis
mean() |> # On calcule la moyenne
round(digits = 2) # On arrondit
## [1] 3.53
%>%
et le
|>
Une première question naturelle est “Quelle est la différence?”. La
différence fondamentale est que %>%
est une
fonction qui s’écrit %>%(LHS, RHS)
où
RHS
est une fonction et LHS
est une expression
R
quelconque, alors que le |>
est un simple
raccourci syntaxique , i.e. a |> f()
est interprété
exactement comme f(a)
.
On peut s’en rendre compte en examinant deux expressions construites
avec |>
et %>%
quote(2 %>% sqrt()) ## pas de modifications
## 2 %>% sqrt()
quote(2 |> sqrt()) ## reinterprétation comme sqrt(2)
## sqrt(2)
Cette simplification fait que ce dernier est plus efficace, comme illustré sur notre suite d’opérations simples:
microbenchmark(native = {10:15 |>
sqrt() |>
mean() |>
round(digits = 2)},
magrittr = {10:15 %>%
sqrt() %>%
mean() %>%
round(digits = 2)}) %>%
summary()
Cependant, en pratique, dans l’usage classique impliquant des tableaux de données, ce gain est négligeable au vu des différentes manipulations (notamment les copies des tableaux) effectuées.
library(dplyr) # Pour la manipulation de data.frame
microbenchmark(native = iris |>
select_if(is.numeric) |>
mutate_all(sqrt) |>
summarise_all(mean) |>
summarise_all(round, digits = 2),
magritr = iris %>%
select_if(is.numeric) %>%
mutate_all(sqrt) %>%
summarise_all(mean) %>%
summarise_all(round, digits = 2)) %>%
summary()
Cette subtilité peut induire des comportements insidieux, notamment
dans la manipulation d’expressions de R
, où l’on préferera
sans doute le |>
natif qui reproduit exactement le
R
de base.
Par exemple, si on reproduire le code suivant de manière séquentielle:
quote(print("Hello"))
## print("Hello")
on peut procéder “naturellement” avec le pipe natif:
"Hello" |>
print() |>
quote()
## print("Hello")
Cependant, cette syntaxe ne fonctionnerait pas avec le pipe
%>%
"Hello" %>%
print() %>%
quote()
## .
A noter une différence importante qui est la manière de gérer
l’argument, c’est à dire la position de l’argument
LHS
dans la fonction RHS
.
Typiquement, pour écrire:
lm(Sepal.Length ~ Sepal.Width, data = iris[iris$Species == "setosa",])
la version tidy avec %>%
est
%>%
iris filter(Species == "setosa") %>%
lm(Sepal.Length ~ Sepal.Width, data = .)
où on a utilisé le .
pour spécifier “ce qu’il y avait
avant”, ce qui a permis de spécifier comme argument data
le
résultat des traitements précédents.
Cette possibilité existe dans le pipe natif, mais
seulement dans la version R 4.2.+
. Et on
utilisera le placeholder _
au lieu de
.
.
|>
iris filter(Species == "setosa") |>
lm(Sepal.Length ~ Sepal.Width, data = _)
En ce qui concerne l’écriture de fonctions, les deux expressions ci-dessous sont équivalentes :
function(x) x + 1
## function(x) x + 1
+ 1 \(x) x
## \(x) x + 1
Cette nouvelle écriture, permet principalement d’économiser le nombre de caractères.
En combinant avec le pipe natif, on obtiendrait :
|>
mtcars lm(mpg ~ disp, data = x))() (\(x)
##
## Call:
## lm(formula = mpg ~ disp, data = x)
##
## Coefficients:
## (Intercept) disp
## 29.59985 -0.04122
A la place de :
|>
mtcars function(x) lm(mpg ~ disp, data = x))() (
##
## Call:
## lm(formula = mpg ~ disp, data = x)
##
## Coefficients:
## (Intercept) disp
## 29.59985 -0.04122
et de la formule suivante utilisant le pipe %>%
:
%>%
mtcars lm(mpg ~ disp, data = .)
##
## Call:
## lm(formula = mpg ~ disp, data = .)
##
## Coefficients:
## (Intercept) disp
## 29.59985 -0.04122
Pour une discussion exhaustive sur les différences entre les deux pipes, on peut consulter la discussion StackOverflow sur le sujet.
L’IDE RStudio fait l’objet d’un travail de développement intense. Sur les derniers mois, quelques évolutions notables concernent:
L’apprentissage de git, notamment la gestion des branches, est souvent considéré comme complexe malgré la profusion de ressources existantes (par exemple: git manual). Des interfaces ludiques existent pour (re)-découvrir et s’entraîner à la gestion des branches. Nous avons exploré Learning branching.