Attaching package: 'dplyr'
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
dplyr
dplyr
, un package du tidyverse
simplifie grandement la manipulation de tableaux de données. Il permet de renommer, ordonner, sélectionner et crééer de nouvelles colonnes, filtrer des lignes, faire facilement des résumés groupés et des sous-jeux de données.
Celles et ceux familiers avec SQL, et plus largement les bases de données, seront en terrain connu.
tibble
dplyr
comme le reste du tidyverse
s’appuie massivement sur les data.frame
, dont la méthode d’affichage n’était pas optimale. Le package tibble
introduit une classe légèrement modifiée de data.frame
s dont la conséquence la plus visibles est la méthode d’affichage : à la fois plus compacte et plus informative.
Attaching package: 'dplyr'
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
Comparez l’affichage par défaut de ça : (je ne l’affiche pas ici par empathie envers vos molettes de souris) :
# berk iris
à ça :
%>% as_tibble() # <3 iris
# A tibble: 150 × 5
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl> <dbl> <dbl> <dbl> <fct>
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
7 4.6 3.4 1.4 0.3 setosa
8 5 3.4 1.5 0.2 setosa
9 4.4 2.9 1.4 0.2 setosa
10 4.9 3.1 1.5 0.1 setosa
# ℹ 140 more rows
Les fonctions de dplyr
sont toutes des verbes, qui traduisent bien l’action à mener.
Le premier argument est toujours un tibble et la sortie est aussi un tibble. Ce qui se marie à merveille avec le pipe de maggritr %>%
ou le pipe désormais embarqué dans R |>
.
La plupart des commandes présentées ci-dessous sont tellement explicites qu’elles se passent de commentaires.
select
pour sélectionner des colonnesIndexer par les noms de colonnes. Ici on ne retient que celles passées à select
:
%>%
starwars select(name, height, sex, species)
# A tibble: 87 × 4
name height sex species
<chr> <int> <chr> <chr>
1 Luke Skywalker 172 male Human
2 C-3PO 167 none Droid
3 R2-D2 96 none Droid
4 Darth Vader 202 male Human
5 Leia Organa 150 female Human
6 Owen Lars 178 male Human
7 Beru Whitesun Lars 165 female Human
8 R5-D4 97 none Droid
9 Biggs Darklighter 183 male Human
10 Obi-Wan Kenobi 182 male Human
# ℹ 77 more rows
Mais on peut aussi utiliser une indexation positionnelle
%>%
starwars select(1:5)
# A tibble: 87 × 5
name height mass hair_color skin_color
<chr> <int> <dbl> <chr> <chr>
1 Luke Skywalker 172 77 blond fair
2 C-3PO 167 75 <NA> gold
3 R2-D2 96 32 <NA> white, blue
4 Darth Vader 202 136 none white
5 Leia Organa 150 49 brown light
6 Owen Lars 178 120 brown, grey light
7 Beru Whitesun Lars 165 75 brown light
8 R5-D4 97 32 <NA> white, red
9 Biggs Darklighter 183 84 black light
10 Obi-Wan Kenobi 182 77 auburn, white fair
# ℹ 77 more rows
Et négative :
%>%
starwars select(-name, -height, -mass, -hair_color)
# A tibble: 87 × 10
skin_color eye_color birth_year sex gender homeworld species films vehicles
<chr> <chr> <dbl> <chr> <chr> <chr> <chr> <lis> <list>
1 fair blue 19 male mascu… Tatooine Human <chr> <chr>
2 gold yellow 112 none mascu… Tatooine Droid <chr> <chr>
3 white, bl… red 33 none mascu… Naboo Droid <chr> <chr>
4 white yellow 41.9 male mascu… Tatooine Human <chr> <chr>
5 light brown 19 fema… femin… Alderaan Human <chr> <chr>
6 light blue 52 male mascu… Tatooine Human <chr> <chr>
7 light blue 47 fema… femin… Tatooine Human <chr> <chr>
8 white, red red NA none mascu… Tatooine Droid <chr> <chr>
9 light brown 24 male mascu… Tatooine Human <chr> <chr>
10 fair blue-gray 57 male mascu… Stewjon Human <chr> <chr>
# ℹ 77 more rows
# ℹ 1 more variable: starships <list>
Ou encore des helpers fournis par tidyselect
(allez donc jeter un oeil à ?tidyselect::language
) :
%>%
starwars select(name, species, ends_with("color"))
# A tibble: 87 × 5
name species hair_color skin_color eye_color
<chr> <chr> <chr> <chr> <chr>
1 Luke Skywalker Human blond fair blue
2 C-3PO Droid <NA> gold yellow
3 R2-D2 Droid <NA> white, blue red
4 Darth Vader Human none white yellow
5 Leia Organa Human brown light brown
6 Owen Lars Human brown, grey light blue
7 Beru Whitesun Lars Human brown light blue
8 R5-D4 Droid <NA> white, red red
9 Biggs Darklighter Human black light brown
10 Obi-Wan Kenobi Human auburn, white fair blue-gray
# ℹ 77 more rows
rename
: pour renommer des colonnesrename
est bien pratique pour renommer des colonnes
%>%
starwars rename(id=name, sp=species) %>%
select(id, sp)
# A tibble: 87 × 2
id sp
<chr> <chr>
1 Luke Skywalker Human
2 C-3PO Droid
3 R2-D2 Droid
4 Darth Vader Human
5 Leia Organa Human
6 Owen Lars Human
7 Beru Whitesun Lars Human
8 R5-D4 Droid
9 Biggs Darklighter Human
10 Obi-Wan Kenobi Human
# ℹ 77 more rows
Sachez que vous pouvez aussi combiner select
et rename
comme suit :
%>%
starwars select(id=name, sp=species)
# A tibble: 87 × 2
id sp
<chr> <chr>
1 Luke Skywalker Human
2 C-3PO Droid
3 R2-D2 Droid
4 Darth Vader Human
5 Leia Organa Human
6 Owen Lars Human
7 Beru Whitesun Lars Human
8 R5-D4 Droid
9 Biggs Darklighter Human
10 Obi-Wan Kenobi Human
# ℹ 77 more rows
slice
: selection positionnelle des lignesVous pouvez passer un ou plusieurs ids de colonnes :
<- c(1, 5, 8)
keep_these %>% slice(keep_these) starwars
# A tibble: 3 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Luke Sky… 172 77 blond fair blue 19 male mascu…
2 Leia Org… 150 49 brown light brown 19 fema… femin…
3 R5-D4 97 32 <NA> white, red red NA none mascu…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
C’est plus lisible que starwars[keep_these]
et ça reste pipable : que demande le peuple ?
Naturellement vous pouvez slicer négativement.
filter
: selection conditionnelle des lignesParfait pour inspecter, analyser des sous-jeux de données :
%>%
starwars filter(species=="Human")
# A tibble: 35 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Luke Sk… 172 77 blond fair blue 19 male mascu…
2 Darth V… 202 136 none white yellow 41.9 male mascu…
3 Leia Or… 150 49 brown light brown 19 fema… femin…
4 Owen La… 178 120 brown, gr… light blue 52 male mascu…
5 Beru Wh… 165 75 brown light blue 47 fema… femin…
6 Biggs D… 183 84 black light brown 24 male mascu…
7 Obi-Wan… 182 77 auburn, w… fair blue-gray 57 male mascu…
8 Anakin … 188 84 blond fair blue 41.9 male mascu…
9 Wilhuff… 180 NA auburn, g… fair blue 64 male mascu…
10 Han Solo 180 80 brown fair brown 29 male mascu…
# ℹ 25 more rows
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
On peut combiner les conditions, y compris sur les numeric
. Ici, on ne retient que les petites brunes (humaines) aux yeux non bleus :
%>%
starwars filter(species=="Human", sex=="female", height <= 170, eye_color != "blue")
# A tibble: 3 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Leia Org… 150 49 brown light brown 19 fema… femin…
2 Shmi Sky… 163 NA black fair brown 72 fema… femin…
3 Dormé 165 NA brown light brown NA fema… femin…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
C’est peut-être le moment de réviser les opérateurs logiques que nous avons vu à l’apéritif.
Si vous optez, positivement ou négativement, pour plus d’un critère concernant une colonne, vous pouvez utiliser %in%
:
%>%
starwars filter(species %in% c("Human", "Droid"), # humans and droids
!(hair_color %in% c("brown", "blond"))) # NO brown or blond hair
# A tibble: 25 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 C-3PO 167 75 <NA> gold yellow 112 none mascu…
2 R2-D2 96 32 <NA> white, bl… red 33 none mascu…
3 Darth V… 202 136 none white yellow 41.9 male mascu…
4 Owen La… 178 120 brown, gr… light blue 52 male mascu…
5 R5-D4 97 32 <NA> white, red red NA none mascu…
6 Biggs D… 183 84 black light brown 24 male mascu…
7 Obi-Wan… 182 77 auburn, w… fair blue-gray 57 male mascu…
8 Wilhuff… 180 NA auburn, g… fair blue 64 male mascu…
9 Palpati… 170 75 grey pale yellow 82 male mascu…
10 Boba Fe… 183 78.2 black fair brown 31.5 male mascu…
# ℹ 15 more rows
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
mutate
: pour créer de nouvelles colonnesBien utile pour calculer l’indice de masse corporelle de ce beau monde par exemple :
%>%
starwars select(name, height, mass, species) %>%
mutate(bmi=mass/((height/100)^2))
# A tibble: 87 × 5
name height mass species bmi
<chr> <int> <dbl> <chr> <dbl>
1 Luke Skywalker 172 77 Human 26.0
2 C-3PO 167 75 Droid 26.9
3 R2-D2 96 32 Droid 34.7
4 Darth Vader 202 136 Human 33.3
5 Leia Organa 150 49 Human 21.8
6 Owen Lars 178 120 Human 37.9
7 Beru Whitesun Lars 165 75 Human 27.5
8 R5-D4 97 32 Droid 34.0
9 Biggs Darklighter 183 84 Human 25.1
10 Obi-Wan Kenobi 182 77 Human 23.2
# ℹ 77 more rows
Vous pouvez utiliser “immédiatement” une colonne créé par mutate
. C’est tellement beau :
<- starwars %>%
sw select(name, height, mass, species) %>%
mutate(height=height/100, bmi=mass/height^2)
sw
# A tibble: 87 × 5
name height mass species bmi
<chr> <dbl> <dbl> <chr> <dbl>
1 Luke Skywalker 1.72 77 Human 26.0
2 C-3PO 1.67 75 Droid 26.9
3 R2-D2 0.96 32 Droid 34.7
4 Darth Vader 2.02 136 Human 33.3
5 Leia Organa 1.5 49 Human 21.8
6 Owen Lars 1.78 120 Human 37.9
7 Beru Whitesun Lars 1.65 75 Human 27.5
8 R5-D4 0.97 32 Droid 34.0
9 Biggs Darklighter 1.83 84 Human 25.1
10 Obi-Wan Kenobi 1.82 77 Human 23.2
# ℹ 77 more rows
mutate
est un outil très puissant pour mettre de l’ordre et nettoyer vos jeux de données. Pour les facteurs et les chaînes de caractères, il se marie à merveille avec les fonctions de forcats
et stringr
respectivement. Minute papillon, nous les verrons un peu plus tard.
Avant de quitter mutate
, sa variante transmute
crée de nouvelles colonnes et omet toutes les autres :
%>%
starwars transmute(name, sex, height=height/100)
# A tibble: 87 × 3
name sex height
<chr> <chr> <dbl>
1 Luke Skywalker male 1.72
2 C-3PO none 1.67
3 R2-D2 none 0.96
4 Darth Vader male 2.02
5 Leia Organa female 1.5
6 Owen Lars male 1.78
7 Beru Whitesun Lars female 1.65
8 R5-D4 none 0.97
9 Biggs Darklighter male 1.83
10 Obi-Wan Kenobi male 1.82
# ℹ 77 more rows
arrange
: trier les lignesUn verbe très pratique pour trier les données :
%>%
sw arrange(bmi)
# A tibble: 87 × 5
name height mass species bmi
<chr> <dbl> <dbl> <chr> <dbl>
1 Wat Tambor 1.93 48 Skakoan 12.9
2 Padmé Amidala 1.85 45 Human 13.1
3 Adi Gallia 1.84 50 Tholothian 14.8
4 Sly Moore 1.78 48 <NA> 15.1
5 Roos Tarpals 2.24 82 Gungan 16.3
6 Lama Su 2.29 88 Kaminoan 16.8
7 Jar Jar Binks 1.96 66 Gungan 17.2
8 Ayla Secura 1.78 55 Twi'lek 17.4
9 Shaak Ti 1.78 57 Togruta 18.0
10 Barriss Offee 1.66 50 Mirialan 18.1
# ℹ 77 more rows
Ici, par d’ex aequo sur la colonne bmi
mais on aurait pu ajouter une autre colonne dans arrange
en cas d’égalité.
Pour trier par ordre descendant, il nous faut ajouter desc
pour que les plus voluptueux passe en premier. Notez Yoda en troisième position. Ça c’est de la science, pas de la fiction. En vrai, cela questionne aussi (sans doute) le domaine de validité du BMI.
%>% arrange(desc(bmi)) sw
# A tibble: 87 × 5
name height mass species bmi
<chr> <dbl> <dbl> <chr> <dbl>
1 Jabba Desilijic Tiure 1.75 1358 Hutt 443.
2 Dud Bolt 0.94 45 Vulptereen 50.9
3 Yoda 0.66 17 Yoda's species 39.0
4 Owen Lars 1.78 120 Human 37.9
5 IG-88 2 140 Droid 35
6 R2-D2 0.96 32 Droid 34.7
7 Grievous 2.16 159 Kaleesh 34.1
8 R5-D4 0.97 32 Droid 34.0
9 Jek Tono Porkins 1.8 110 <NA> 34.0
10 Darth Vader 2.02 136 Human 33.3
# ℹ 77 more rows
Vous pourriez être tentée de combiner arrange
puis slice
pour ne retenir que les n
plus (ou moins) quelque chose :
%>%
sw arrange(desc(bmi)) %>%
slice(1:5)
# A tibble: 5 × 5
name height mass species bmi
<chr> <dbl> <dbl> <chr> <dbl>
1 Jabba Desilijic Tiure 1.75 1358 Hutt 443.
2 Dud Bolt 0.94 45 Vulptereen 50.9
3 Yoda 0.66 17 Yoda's species 39.0
4 Owen Lars 1.78 120 Human 37.9
5 IG-88 2 140 Droid 35
Mais peut-être préférerez vous l’alternative compacte de slice_*
et pièces rattachées :
%>% slice_max(bmi, n=5) sw
# A tibble: 5 × 5
name height mass species bmi
<chr> <dbl> <dbl> <chr> <dbl>
1 Jabba Desilijic Tiure 1.75 1358 Hutt 443.
2 Dud Bolt 0.94 45 Vulptereen 50.9
3 Yoda 0.66 17 Yoda's species 39.0
4 Owen Lars 1.78 120 Human 37.9
5 IG-88 2 140 Droid 35
count
: compter des lignes sur des critères en colonnesPour obtenir des résumés, vous pouvez utiliser count
qui rajouter une colonne qui peut se révéler fort utile :
%>%
starwars count(species, name="N") %>% # if you omit `name`, count create `n` by default
arrange(desc(N)) %>%
slice_head(n=5)
# A tibble: 5 × 2
species N
<chr> <int>
1 Human 35
2 Droid 6
3 <NA> 4
4 Gungan 3
5 Kaminoan 2
Et si vous voulez garder les autres colonnes, add_count
est votre nouveau copain :
%>%
starwars select(name, sex, species) %>%
add_count(species) %>%
filter(n >= 3)
# A tibble: 48 × 4
name sex species n
<chr> <chr> <chr> <int>
1 Luke Skywalker male Human 35
2 C-3PO none Droid 6
3 R2-D2 none Droid 6
4 Darth Vader male Human 35
5 Leia Organa female Human 35
6 Owen Lars male Human 35
7 Beru Whitesun Lars female Human 35
8 R5-D4 none Droid 6
9 Biggs Darklighter male Human 35
10 Obi-Wan Kenobi male Human 35
# ℹ 38 more rows
summarise
: résumés et résumés groupésCréeons d’abord un mini starwars, sur lequel nous allons supprimer les lignes avec des données manquantes pour la colonne ehight
puis illustrons les vertus de summary
:
<- starwars %>%
sw select(species, sex, height) %>%
filter(species %in% c("Human", "Droid"), !is.na(height))
%>% summarise(height=mean(height)) sw
# A tibble: 1 × 1
height
<dbl>
1 171.
Pas dingue hein. Peut être qu’un résumé par espèce et par sexe serait plus intéressant ? group_by
est votre allié. On peut rajouter d’autres fonctions de résumé au passage :
%>%
sw group_by(species, sex) %>%
summarise(mean_height=mean(height),
sd_height=sd(height))
`summarise()` has grouped output by 'species'. You can override using the
`.groups` argument.
# A tibble: 3 × 4
# Groups: species [2]
species sex mean_height sd_height
<chr> <chr> <dbl> <dbl>
1 Droid none 131. 49.1
2 Human female 164. 11.9
3 Human male 182. 8.16
accross
est très utile ici pour résumer plusieurs colonnes, éventuellement avec plusieurs fonctions de résumé :
%>%
starwars select(species, height, mass) %>%
na.omit() %>%
filter(species %in% c("Human", "Droid")) %>%
group_by(species) %>%
summarise(across(c(height, mass), list(mean=mean, sd=sd), .names = "{.col}_{fn}"))
# A tibble: 2 × 5
species height_mean height_sd mass_mean mass_sd
<chr> <dbl> <dbl> <dbl> <dbl>
1 Droid 140 52.0 69.8 51.0
2 Human 180. 11.5 81.3 19.3
join
: combiner des tablesEn analyse de données, nous avons souvent des tables à réunir via une colonne commune (par exemple un id
). La famille de join
est précieuse.
Nous allons utiliser deux petits jeux de données disponibles avec dplyr
:
band_members
# A tibble: 3 × 2
name band
<chr> <chr>
1 Mick Stones
2 John Beatles
3 Paul Beatles
band_instruments
# A tibble: 3 × 2
name plays
<chr> <chr>
1 John guitar
2 Paul bass
3 Keith guitar
Nous pouvons combiner ces tables avec left_join
et ses variantes.
left_join(band_members, band_instruments, by="name")
# A tibble: 3 × 3
name band plays
<chr> <chr> <chr>
1 Mick Stones <NA>
2 John Beatles guitar
3 Paul Beatles bass
right_join(band_members, band_instruments, by="name")
# A tibble: 3 × 3
name band plays
<chr> <chr> <chr>
1 John Beatles guitar
2 Paul Beatles bass
3 Keith <NA> guitar
full_join(band_members, band_instruments, by="name")
# A tibble: 4 × 3
name band plays
<chr> <chr> <chr>
1 Mick Stones <NA>
2 John Beatles guitar
3 Paul Beatles bass
4 Keith <NA> guitar
❤ Placé dans le domaine public par Vincent Bonhomme