8 dplyr
dplyr est l’un des packages les plus connus du tidyverse. Il facilite le traitement et la manipulation des tableaux de données (qu’il s’agisse de data frame ou de tibble). Il propose une syntaxe claire et cohérente, sous formes de verbes
correspondant à des fonctions.
dplyr part du principe que les données sont tidy (chaque variable est une colonne, chaque observation est une ligne, voir Chapitre 5). Les verbes de dplyr prennent en entrée un tableau de données1 (data frame ou tibble) et renvoient systématiquement un tibble.
Dans ce qui suit on va utiliser le jeu de données nycflights13, contenu dans l’extension du même nom (qu’il faut donc avoir installée). Celui-ci correspond aux données de tous les vols au départ d’un des trois aéroports de New-York en 2013. Il a la particularité d’être réparti en trois tables :
-
nycflights13::flights
contient des informations sur les vols : date, départ, destination, horaires, retard… -
nycflights13::airports
contient des informations sur les aéroports -
nycflights13::airlines
contient des données sur les compagnies aériennes
On va charger les trois tables du jeu de données :
Normalement trois objets correspondant aux trois tables ont dû apparaître dans votre environnement.
8.1 Opérations sur les lignes
8.1.1 filter()
dplyr::filter()
sélectionne des lignes d’un tableau de données selon une condition. On lui passe en paramètre un test, et seules les lignes pour lesquelles ce test renvoi TRUE
(vrai) sont conservées2.
2 Si le test renvoie faux (FALSE
) ou une valeur manquante (NA
), les lignes correspondantes ne seront donc pas sélectionnées.
Par exemple, si on veut sélectionner les vols du mois de janvier, on peut filtrer sur la variable month de la manière suivante :
# A tibble: 27,004 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# ℹ 26,994 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Cela peut s’écrire plus simplement avec un pipe :
# A tibble: 27,004 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# ℹ 26,994 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Si l’on veut uniquement les vols avec un retard au départ (variable dep_delay) compris entre 10 et 15 minutes :
# A tibble: 14,919 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 611 600 11 945 931
2 2013 1 1 623 610 13 920 915
3 2013 1 1 743 730 13 1107 1100
4 2013 1 1 743 730 13 1059 1056
5 2013 1 1 851 840 11 1215 1206
6 2013 1 1 912 900 12 1241 1220
7 2013 1 1 914 900 14 1058 1043
8 2013 1 1 920 905 15 1039 1025
9 2013 1 1 1011 1001 10 1133 1128
10 2013 1 1 1112 1100 12 1440 1438
# ℹ 14,909 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Si l’on passe plusieurs arguments à dplyr::filter()
, celui-ci rajoute automatiquement une condition ET. La ligne ci-dessus peut donc également être écrite de la manière suivante, avec le même résultat :
Enfin, on peut également placer des fonctions dans les tests, qui nous permettent par exemple de sélectionner les vols avec la plus grande distance :
# A tibble: 342 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 857 900 -3 1516 1530
2 2013 1 2 909 900 9 1525 1530
3 2013 1 3 914 900 14 1504 1530
4 2013 1 4 900 900 0 1516 1530
5 2013 1 5 858 900 -2 1519 1530
6 2013 1 6 1019 900 79 1558 1530
7 2013 1 7 1042 900 102 1620 1530
8 2013 1 8 901 900 1 1504 1530
9 2013 1 9 641 900 1301 1242 1530
10 2013 1 10 859 900 -1 1449 1530
# ℹ 332 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Il est important de noter que dplyr procède à une évaluation contextuelle des expressions qui lui sont passées. Ainsi, on peut indiquer directement le nom d’une variable et dplyr l’interprétera dans le contexte du tableau de données, c’est-à-dire regardera s’il existe une colonne portant ce nom dans le tableau.
Dans l’expression flights |> filter(month == 1)
, month
est interprété comme la colonne month du tableau flights
, à savoir flights$month
.
Il est également possible d’indiquer des objets extérieurs au tableau :
# A tibble: 24,951 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 2 1 456 500 -4 652 648
2 2013 2 1 520 525 -5 816 820
3 2013 2 1 527 530 -3 837 829
4 2013 2 1 532 540 -8 1007 1017
5 2013 2 1 540 540 0 859 850
6 2013 2 1 552 600 -8 714 715
7 2013 2 1 552 600 -8 919 910
8 2013 2 1 552 600 -8 655 709
9 2013 2 1 553 600 -7 833 815
10 2013 2 1 553 600 -7 821 825
# ℹ 24,941 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Cela fonctionne car il n’y a pas de colonne m dans flights
. Dès lors, dplyr regarde s’il existe un objet m
dans l’environnement de travail.
Par contre, si une colonne existe dans le tableau, elle aura priorité sur les objets du même nom dans l’environnement. Dans l’exemple ci-dessous, le résultat obtenu n’est pas celui voulu. Il est interprété comme sélectionner toutes les lignes où la colonne mois est égale à elle-même
et donc cela sélectionne toutes les lignes du tableau.
# A tibble: 336,776 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# ℹ 336,766 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Afin de distinguer ce qui correspond à une colonne du tableau et à un objet de l’environnement, on pourra avoir recours à .data
et .env
(voir help(".env", package = "rlang")
).
# A tibble: 28,834 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 3 1 4 2159 125 318 56
2 2013 3 1 50 2358 52 526 438
3 2013 3 1 117 2245 152 223 2354
4 2013 3 1 454 500 -6 633 648
5 2013 3 1 505 515 -10 746 810
6 2013 3 1 521 530 -9 813 827
7 2013 3 1 537 540 -3 856 850
8 2013 3 1 541 545 -4 1014 1023
9 2013 3 1 549 600 -11 639 703
10 2013 3 1 550 600 -10 747 801
# ℹ 28,824 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
8.1.2 slice()
Le verbe dplyr::slice()
sélectionne des lignes du tableau selon leur position. On lui passe un chiffre ou un vecteur de chiffres.
Si l’on souhaite sélectionner la 345e ligne du tableau airports
:
# A tibble: 1 × 8
faa name lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 CYF Chefornak Airport 60.1 -164. 40 -9 A America/Anchorage
Si l’on veut sélectionner les 5 premières lignes :
# A tibble: 5 × 8
faa name lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A America/New…
2 06A Moton Field Municipal Airport 32.5 -85.7 264 -6 A America/Chi…
3 06C Schaumburg Regional 42.0 -88.1 801 -6 A America/Chi…
4 06N Randall Airport 41.4 -74.4 523 -5 A America/New…
5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A America/New…
8.1.3 arrange()
dplyr::arrange()
réordonne les lignes d’un tableau selon une ou plusieurs colonnes.
Ainsi, si l’on veut trier le tableau flights
selon le retard au départ, dans l’ordre croissant :
# A tibble: 336,776 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 12 7 2040 2123 -43 40 2352
2 2013 2 3 2022 2055 -33 2240 2338
3 2013 11 10 1408 1440 -32 1549 1559
4 2013 1 11 1900 1930 -30 2233 2243
5 2013 1 29 1703 1730 -27 1947 1957
6 2013 8 9 729 755 -26 1002 955
7 2013 10 23 1907 1932 -25 2143 2143
8 2013 3 30 2030 2055 -25 2213 2250
9 2013 3 2 1431 1455 -24 1601 1631
10 2013 5 5 934 958 -24 1225 1309
# ℹ 336,766 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
On peut trier selon plusieurs colonnes. Par exemple selon le mois, puis selon le retard au départ :
# A tibble: 336,776 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 11 1900 1930 -30 2233 2243
2 2013 1 29 1703 1730 -27 1947 1957
3 2013 1 12 1354 1416 -22 1606 1650
4 2013 1 21 2137 2159 -22 2232 2316
5 2013 1 20 704 725 -21 1025 1035
6 2013 1 12 2050 2110 -20 2310 2355
7 2013 1 12 2134 2154 -20 4 50
8 2013 1 14 2050 2110 -20 2329 2355
9 2013 1 4 2140 2159 -19 2241 2316
10 2013 1 11 1947 2005 -18 2209 2230
# ℹ 336,766 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Si l’on veut trier selon une colonne par ordre décroissant, on lui applique la fonction dplyr::desc()
:
# A tibble: 336,776 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 6 15 1432 1935 1137 1607 2120
3 2013 1 10 1121 1635 1126 1239 1810
4 2013 9 20 1139 1845 1014 1457 2210
5 2013 7 22 845 1600 1005 1044 1815
6 2013 4 10 1100 1900 960 1342 2211
7 2013 3 17 2321 810 911 135 1020
8 2013 6 27 959 1900 899 1236 2226
9 2013 7 22 2257 759 898 121 1026
10 2013 12 5 756 1700 896 1058 2020
# ℹ 336,766 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Combiné avec dplyr::slice()
, dplyr::arrange()
permet par exemple de sélectionner les trois vols ayant eu le plus de retard :
# A tibble: 3 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 6 15 1432 1935 1137 1607 2120
3 2013 1 10 1121 1635 1126 1239 1810
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
8.1.4 slice_sample()
dplyr::slice_sample()
permet de sélectionner aléatoirement un nombre de lignes ou une fraction des lignes d’un tableau. Ainsi si l’on veut choisir 5 lignes au hasard dans le tableau airports
:
# A tibble: 5 × 8
faa name lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 ECG Elizabeth City Cgas Rgnl 36.3 -76.2 12 -5 A America/New_York
2 MQB Macomb Municipal Airport 40.5 -90.7 707 -6 U America/Chicago
3 GSO Piedmont Triad 36.1 -79.9 925 -5 A America/New_York
4 BFI Boeing Fld King Co Intl 47.5 -122. 21 -8 A America/Los_Ang…
5 LIH Lihue 22.0 -159. 153 -10 N Pacific/Honolulu
Si l’on veut tirer au hasard 10% des lignes de flights
:
# A tibble: 33,677 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 12 9 2233 2100 93 2326 2206
2 2013 5 10 752 755 -3 1035 1045
3 2013 4 2 1022 1015 7 1211 1205
4 2013 4 2 955 1000 -5 1052 1112
5 2013 6 26 1404 1359 5 1632 1632
6 2013 2 20 2140 2130 10 2258 2255
7 2013 6 24 1114 1115 -1 1351 1400
8 2013 2 25 1122 1130 -8 1426 1446
9 2013 7 18 2202 2142 20 2326 2259
10 2013 12 2 1822 1800 22 2105 2037
# ℹ 33,667 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Ces fonctions sont utiles notamment pour faire de l’“échantillonnage”
en tirant au hasard un certain nombre d’observations du tableau.
8.1.5 distinct()
dplyr::distinct()
filtre les lignes du tableau pour ne conserver que les lignes distinctes, en supprimant toutes les lignes en double.
# A tibble: 365 × 2
day month
<int> <int>
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
6 6 1
7 7 1
8 8 1
9 9 1
10 10 1
# ℹ 355 more rows
On peut lui spécifier une liste de variables : dans ce cas, pour toutes les observations ayant des valeurs identiques pour les variables en question, dplyr::distinct()
ne conservera que la première d’entre elles.
# A tibble: 365 × 2
month day
<int> <int>
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
6 1 6
7 1 7
8 1 8
9 1 9
10 1 10
# ℹ 355 more rows
L’option .keep_all
permet, dans l’opération précédente, de conserver l’ensemble des colonnes du tableau :
# A tibble: 365 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 2 42 2359 43 518 442
3 2013 1 3 32 2359 33 504 442
4 2013 1 4 25 2359 26 505 442
5 2013 1 5 14 2359 15 503 445
6 2013 1 6 16 2359 17 451 442
7 2013 1 7 49 2359 50 531 444
8 2013 1 8 454 500 -6 625 648
9 2013 1 9 2 2359 3 432 444
10 2013 1 10 3 2359 4 426 437
# ℹ 355 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
8.2 Opérations sur les colonnes
8.2.1 select()
dplyr::select()
permet de sélectionner des colonnes d’un tableau de données. Ainsi, si l’on veut extraire les colonnes lat
et lon
du tableau airports
:
# A tibble: 1,458 × 2
lat lon
<dbl> <dbl>
1 41.1 -80.6
2 32.5 -85.7
3 42.0 -88.1
4 41.4 -74.4
5 31.1 -81.4
6 36.4 -82.2
7 41.5 -84.5
8 42.9 -76.8
9 39.8 -76.6
10 48.1 -123.
# ℹ 1,448 more rows
Si on fait précéder le nom d’un -
, la colonne est éliminée plutôt que sélectionnée :
# A tibble: 1,458 × 6
faa name alt tz dst tzone
<chr> <chr> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 1044 -5 A America/New_York
2 06A Moton Field Municipal Airport 264 -6 A America/Chicago
3 06C Schaumburg Regional 801 -6 A America/Chicago
4 06N Randall Airport 523 -5 A America/New_York
5 09J Jekyll Island Airport 11 -5 A America/New_York
6 0A9 Elizabethton Municipal Airport 1593 -5 A America/New_York
7 0G6 Williams County Airport 730 -5 A America/New_York
8 0G7 Finger Lakes Regional Airport 492 -5 A America/New_York
9 0P2 Shoestring Aviation Airfield 1000 -5 U America/New_York
10 0S9 Jefferson County Intl 108 -8 A America/Los_Angeles
# ℹ 1,448 more rows
dplyr::select()
comprend toute une série de fonctions facilitant la sélection de multiples colonnes. Par exemple, dplyr::starts_with()
, dplyr::ends_width()
, dplyr::contains()
ou dplyr::matches()
permettent d’exprimer des conditions sur les noms de variables :
# A tibble: 336,776 × 2
dep_time dep_delay
<int> <dbl>
1 517 2
2 533 4
3 542 2
4 544 -1
5 554 -6
6 554 -4
7 555 -5
8 557 -3
9 557 -3
10 558 -2
# ℹ 336,766 more rows
La syntaxe colonne1:colonne2
permet de sélectionner toutes les colonnes situées entre colonne1 et colonne2 incluses3 :
3 À noter que cette opération est un peu plus “fragile” que les autres, car si l’ordre des colonnes change elle peut renvoyer un résultat différent.
# A tibble: 336,776 × 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ℹ 336,766 more rows
dplyr::all_of()
et dplyr::any_of()
permettent de fournir une liste de variables à extraire sous forme de vecteur textuel. Alors que dplyr::all_of()
renverra une erreur si une variable n’est pas trouvée dans le tableau de départ, dplyr::any_of()
sera moins stricte.
# A tibble: 336,776 × 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ℹ 336,766 more rows
Error in `select()`:
ℹ In argument: `all_of(c("century", "year", "month", "day"))`.
Caused by error in `all_of()`:
! Can't subset elements that don't exist.
✖ Element `century` doesn't exist.
Erreur : Can't subset columns that don't exist.
x Column `century` doesn't exist.
# A tibble: 336,776 × 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ℹ 336,766 more rows
dplyr::where()
permets de sélectionner des variables à partir d’une fonction qui renvoie une valeur logique. Par exemple, pour sélectionner seulement les variables textuelles :
# A tibble: 336,776 × 4
carrier tailnum origin dest
<chr> <chr> <chr> <chr>
1 UA N14228 EWR IAH
2 UA N24211 LGA IAH
3 AA N619AA JFK MIA
4 B6 N804JB JFK BQN
5 DL N668DN LGA ATL
6 UA N39463 EWR ORD
7 B6 N516JB EWR FLL
8 EV N829AS LGA IAD
9 B6 N593JB JFK MCO
10 AA N3ALAA LGA ORD
# ℹ 336,766 more rows
dplyr::select()
peut être utilisée pour réordonner les colonnes d’une table en utilisant la fonction dplyr::everything()
, qui sélectionne l’ensemble des colonnes non encore sélectionnées. Ainsi, si l’on souhaite faire passer la colonne name en première position de la table airports
, on peut faire :
# A tibble: 1,458 × 8
name faa lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 Lansdowne Airport 04G 41.1 -80.6 1044 -5 A America/…
2 Moton Field Municipal Airport 06A 32.5 -85.7 264 -6 A America/…
3 Schaumburg Regional 06C 42.0 -88.1 801 -6 A America/…
4 Randall Airport 06N 41.4 -74.4 523 -5 A America/…
5 Jekyll Island Airport 09J 31.1 -81.4 11 -5 A America/…
6 Elizabethton Municipal Airport 0A9 36.4 -82.2 1593 -5 A America/…
7 Williams County Airport 0G6 41.5 -84.5 730 -5 A America/…
8 Finger Lakes Regional Airport 0G7 42.9 -76.8 492 -5 A America/…
9 Shoestring Aviation Airfield 0P2 39.8 -76.6 1000 -5 U America/…
10 Jefferson County Intl 0S9 48.1 -123. 108 -8 A America/…
# ℹ 1,448 more rows
8.2.2 relocate()
Pour réordonner des colonnes, on pourra aussi avoir recours à dplyr::relocate()
en indiquant les premières variables. Il n’est pas nécessaire d’ajouter everything()
car avec dplyr::relocate()
toutes les variables sont conservées.
# A tibble: 1,458 × 8
lon lat name faa alt tz dst tzone
<dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr> <chr>
1 -80.6 41.1 Lansdowne Airport 04G 1044 -5 A America/…
2 -85.7 32.5 Moton Field Municipal Airport 06A 264 -6 A America/…
3 -88.1 42.0 Schaumburg Regional 06C 801 -6 A America/…
4 -74.4 41.4 Randall Airport 06N 523 -5 A America/…
5 -81.4 31.1 Jekyll Island Airport 09J 11 -5 A America/…
6 -82.2 36.4 Elizabethton Municipal Airport 0A9 1593 -5 A America/…
7 -84.5 41.5 Williams County Airport 0G6 730 -5 A America/…
8 -76.8 42.9 Finger Lakes Regional Airport 0G7 492 -5 A America/…
9 -76.6 39.8 Shoestring Aviation Airfield 0P2 1000 -5 U America/…
10 -123. 48.1 Jefferson County Intl 0S9 108 -8 A America/…
# ℹ 1,448 more rows
8.2.3 rename()
Une variante de dplyr::select()
est dplyr::rename()
4, qui permet de renommer facilement des colonnes. On l’utilise en lui passant des paramètres de la forme nouveau_nom = ancien_nom
. Ainsi, si on veut renommer les colonnes lon et lat de airports
en longitude et latitude :
4 Il est également possible de renommer des colonnes directement avec select()
, avec la même syntaxe que pour rename()
.
# A tibble: 1,458 × 8
faa name latitude longitude alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A Amer…
2 06A Moton Field Municipal Airpo… 32.5 -85.7 264 -6 A Amer…
3 06C Schaumburg Regional 42.0 -88.1 801 -6 A Amer…
4 06N Randall Airport 41.4 -74.4 523 -5 A Amer…
5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A Amer…
6 0A9 Elizabethton Municipal Airp… 36.4 -82.2 1593 -5 A Amer…
7 0G6 Williams County Airport 41.5 -84.5 730 -5 A Amer…
8 0G7 Finger Lakes Regional Airpo… 42.9 -76.8 492 -5 A Amer…
9 0P2 Shoestring Aviation Airfield 39.8 -76.6 1000 -5 U Amer…
10 0S9 Jefferson County Intl 48.1 -123. 108 -8 A Amer…
# ℹ 1,448 more rows
Si les noms de colonnes comportent des espaces ou des caractères spéciaux, on peut les entourer de guillemets ("
) ou de quotes inverses (`
) :
8.2.4 rename_with()
La fonction dplyr::rename_with()
permets de renommer plusieurs colonnes d’un coup en transmettant une fonction, par exemple toupper()
qui passe tous les caractères en majuscule.
# A tibble: 1,458 × 8
FAA NAME LAT LON ALT TZ DST TZONE
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A America/…
2 06A Moton Field Municipal Airport 32.5 -85.7 264 -6 A America/…
3 06C Schaumburg Regional 42.0 -88.1 801 -6 A America/…
4 06N Randall Airport 41.4 -74.4 523 -5 A America/…
5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A America/…
6 0A9 Elizabethton Municipal Airport 36.4 -82.2 1593 -5 A America/…
7 0G6 Williams County Airport 41.5 -84.5 730 -5 A America/…
8 0G7 Finger Lakes Regional Airport 42.9 -76.8 492 -5 A America/…
9 0P2 Shoestring Aviation Airfield 39.8 -76.6 1000 -5 U America/…
10 0S9 Jefferson County Intl 48.1 -123. 108 -8 A America/…
# ℹ 1,448 more rows
On pourra notamment utiliser les fonctions du package snakecase
et, en particulier, snakecase::to_snake_case()
que je recommande pour nommer de manière consistante les variables5.
5 Le snake case est une convention typographique en informatique consistant à écrire des ensembles de mots, généralement, en minuscules en les séparant par des tirets bas.
8.2.5 pull()
La fonction dplyr::pull()
permet d’accéder au contenu d’une variable. C’est un équivalent aux opérateurs $
ou [[]]
. On peut lui passer un nom de variable ou bien sa position.
dplyr::pull()
ressemble à la fonction purrr::chuck()
que nous avons déjà abordée (cf. Section 7.4). Cependant, dplyr::pull()
ne fonctionne que sur des tableaux de données tandis que purrr::chuck()
est plus générique et peut s’appliquer à tous types de listes.
8.2.6 mutate()
dplyr::mutate()
permet de créer de nouvelles colonnes dans le tableau de données, en général à partir de variables existantes.
Par exemple, la table airports
contient l’altitude de l’aéroport en pieds. Si l’on veut créer une nouvelle variable alt_m avec l’altitude en mètres, on peut faire :
On peut créer plusieurs nouvelles colonnes en une seule fois, et les expressions successives peuvent prendre en compte les résultats des calculs précédents. L’exemple suivant convertit d’abord la distance en kilomètres dans une variable distance_km, puis utilise cette nouvelle colonne pour calculer la vitesse en km/h.
8.3 Opérations groupées
8.3.1 group_by()
Un élément très important de dplyr est la fonction dplyr::group_by()
. Elle permet de définir des groupes de lignes à partir des valeurs d’une ou plusieurs colonnes. Par exemple, on peut grouper les vols selon leur mois :
# A tibble: 336,776 × 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# ℹ 336,766 more rows
# ℹ 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
Par défaut ceci ne fait rien de visible, à part l’apparition d’une mention Groups dans l’affichage du résultat. Mais à partir du moment où des groupes ont été définis, les verbes comme dplyr::slice()
ou dplyr::mutate()
vont en tenir compte lors de leurs opérations.
Par exemple, si on applique dplyr::slice()
à un tableau préalablement groupé, il va sélectionner les lignes aux positions indiquées pour chaque groupe. Ainsi la commande suivante affiche le premier vol de chaque mois, selon leur ordre d’apparition dans le tableau :
# A tibble: 12 × 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 2 1 456 500 -4 652 648
3 2013 3 1 4 2159 125 318 56
4 2013 4 1 454 500 -6 636 640
5 2013 5 1 9 1655 434 308 2020
6 2013 6 1 2 2359 3 341 350
7 2013 7 1 1 2029 212 236 2359
8 2013 8 1 12 2130 162 257 14
9 2013 9 1 9 2359 10 343 340
10 2013 10 1 447 500 -13 614 648
11 2013 11 1 5 2359 6 352 345
12 2013 12 1 13 2359 14 446 445
# ℹ 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
Idem pour dplyr::mutate()
: les opérations appliquées lors du calcul des valeurs des nouvelles colonnes sont appliquée groupe de lignes par groupe de lignes. Dans l’exemple suivant, on ajoute une nouvelle colonne qui contient le retard moyen du mois correspondant :
# A tibble: 336,776 × 22
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# ℹ 336,766 more rows
# ℹ 14 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>, mean_delay_month <dbl>
Ceci peut permettre, par exemple, de déterminer si un retard donné est supérieur ou inférieur au retard moyen du mois en cours.
dplyr::group_by()
peut aussi être utile avec dplyr::filter()
, par exemple pour sélectionner les vols avec le retard au départ le plus important pour chaque mois :
# A tibble: 12 × 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 10 14 2042 900 702 2255 1127
3 2013 11 3 603 1645 798 829 1913
4 2013 12 5 756 1700 896 1058 2020
5 2013 2 10 2243 830 853 100 1106
6 2013 3 17 2321 810 911 135 1020
7 2013 4 10 1100 1900 960 1342 2211
8 2013 5 3 1133 2055 878 1250 2215
9 2013 6 15 1432 1935 1137 1607 2120
10 2013 7 22 845 1600 1005 1044 1815
11 2013 8 8 2334 1454 520 120 1710
12 2013 9 20 1139 1845 1014 1457 2210
# ℹ 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
Attention : la clause dplyr::roup_by()
marche pour les verbes déjà vus précédemment, sauf pour dplyr::arrange()
, qui par défaut trie la table sans tenir compte des groupes. Pour obtenir un tri par groupe, il faut lui ajouter l’argument .by_group = TRUE
.
On peut voir la différence en comparant les deux résultats suivants :
# A tibble: 336,776 × 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 6 15 1432 1935 1137 1607 2120
3 2013 1 10 1121 1635 1126 1239 1810
4 2013 9 20 1139 1845 1014 1457 2210
5 2013 7 22 845 1600 1005 1044 1815
6 2013 4 10 1100 1900 960 1342 2211
7 2013 3 17 2321 810 911 135 1020
8 2013 6 27 959 1900 899 1236 2226
9 2013 7 22 2257 759 898 121 1026
10 2013 12 5 756 1700 896 1058 2020
# ℹ 336,766 more rows
# ℹ 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
# A tibble: 336,776 × 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 1 10 1121 1635 1126 1239 1810
3 2013 1 1 848 1835 853 1001 1950
4 2013 1 13 1809 810 599 2054 1042
5 2013 1 16 1622 800 502 1911 1054
6 2013 1 23 1551 753 478 1812 1006
7 2013 1 10 1525 900 385 1713 1039
8 2013 1 1 2343 1724 379 314 1938
9 2013 1 2 2131 1512 379 2340 1741
10 2013 1 7 2021 1415 366 2332 1724
# ℹ 336,766 more rows
# ℹ 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
8.3.2 summarise()
dplyr::summarise()
permet d’agréger les lignes du tableau en effectuant une opération résumée
sur une ou plusieurs colonnes. Il s’agit de toutes les fonctions qui prennent en entrée un ensemble de valeurs et renvoie une valeur unique, comme la moyenne (mean()
). Par exemple, si l’on souhaite connaître les retards moyens au départ et à l’arrivée pour l’ensemble des vols du tableau flights
:
flights |>
summarise(
retard_dep = mean(dep_delay, na.rm=TRUE),
retard_arr = mean(arr_delay, na.rm=TRUE)
)
# A tibble: 1 × 2
retard_dep retard_arr
<dbl> <dbl>
1 12.6 6.90
Cette fonction est en général utilisée avec dplyr::group_by()
, puisqu’elle permet du coup d’agréger et de résumer les lignes du tableau groupe par groupe. Si l’on souhaite calculer le délai maximum, le délai minimum et le délai moyen au départ pour chaque mois, on pourra faire :
flights |>
group_by(month) |>
summarise(
max_delay = max(dep_delay, na.rm=TRUE),
min_delay = min(dep_delay, na.rm=TRUE),
mean_delay = mean(dep_delay, na.rm=TRUE)
)
# A tibble: 12 × 4
month max_delay min_delay mean_delay
<int> <dbl> <dbl> <dbl>
1 1 1301 -30 10.0
2 2 853 -33 10.8
3 3 911 -25 13.2
4 4 960 -21 13.9
5 5 878 -24 13.0
6 6 1137 -21 20.8
7 7 1005 -22 21.7
8 8 520 -26 12.6
9 9 1014 -24 6.72
10 10 702 -25 6.24
11 11 798 -32 5.44
12 12 896 -43 16.6
dplyr::summarise()
dispose d’une fonction spéciale dplyr::n()
, qui retourne le nombre de lignes du groupe. Ainsi si l’on veut le nombre de vols par destination, on peut utiliser :
# A tibble: 105 × 2
dest n
<chr> <int>
1 ABQ 254
2 ACK 265
3 ALB 439
4 ANC 8
5 ATL 17215
6 AUS 2439
7 AVL 275
8 BDL 443
9 BGR 375
10 BHM 297
# ℹ 95 more rows
dplyr::n()
peut aussi être utilisée avec dplyr::filter()
et dplyr::mutate()
.
8.3.3 count()
À noter que quand l’on veut compter le nombre de lignes par groupe, on peut utiliser directement la fonction dplyr::count()
. Ainsi le code suivant est identique au précédent :
8.3.4 Grouper selon plusieurs variables
On peut grouper selon plusieurs variables à la fois, il suffit de les indiquer dans la clause du dplyr::group_by()
:
`summarise()` has grouped output by 'month'. You can override using the
`.groups` argument.
# A tibble: 1,113 × 3
# Groups: month [12]
month dest nb
<int> <chr> <int>
1 8 ORD 1604
2 10 ORD 1604
3 5 ORD 1582
4 9 ORD 1582
5 7 ORD 1573
6 6 ORD 1547
7 7 ATL 1511
8 8 ATL 1507
9 8 LAX 1505
10 7 LAX 1500
# ℹ 1,103 more rows
On peut également compter selon plusieurs variables :
# A tibble: 224 × 3
origin dest n
<chr> <chr> <int>
1 JFK LAX 11262
2 LGA ATL 10263
3 LGA ORD 8857
4 JFK SFO 8204
5 LGA CLT 6168
6 EWR ORD 6100
7 JFK BOS 5898
8 LGA MIA 5781
9 JFK MCO 5464
10 EWR BOS 5327
# ℹ 214 more rows
On peut utiliser plusieurs opérations de groupage dans le même pipeline. Ainsi, si l’on souhaite déterminer le couple origine/destination ayant le plus grand nombre de vols selon le mois de l’année, on devra procéder en deux étapes :
- d’abord grouper selon mois, origine et destination pour calculer le nombre de vols
- puis grouper uniquement selon le mois pour sélectionner la ligne avec la valeur maximale.
Au final, on obtient le code suivant :
flights |>
group_by(month, origin, dest) |>
summarise(nb = n()) |>
group_by(month) |>
filter(nb == max(nb))
`summarise()` has grouped output by 'month', 'origin'. You can override using
the `.groups` argument.
# A tibble: 12 × 4
# Groups: month [12]
month origin dest nb
<int> <chr> <chr> <int>
1 1 JFK LAX 937
2 2 JFK LAX 834
3 3 JFK LAX 960
4 4 JFK LAX 935
5 5 JFK LAX 960
6 6 JFK LAX 928
7 7 JFK LAX 985
8 8 JFK LAX 979
9 9 JFK LAX 925
10 10 JFK LAX 965
11 11 JFK LAX 907
12 12 JFK LAX 947
Lorsqu’on effectue un dplyr::group_by()
suivi d’un dplyr::summarise()
, le tableau résultat est automatiquement dégroupé de la dernière variable de regroupement. Ainsi le tableau généré par le code suivant est groupé par month et origin6 :
6 Comme expliqué dans le message affiché dans la console, cela peut être contrôlé avec l’argument .groups
de dplyr::summarise()
, dont les options sont décrites dans l’aide de la fonction.
`summarise()` has grouped output by 'month', 'origin'. You can override using
the `.groups` argument.
# A tibble: 2,313 × 4
# Groups: month, origin [36]
month origin dest nb
<int> <chr> <chr> <int>
1 1 EWR ALB 64
2 1 EWR ATL 362
3 1 EWR AUS 51
4 1 EWR AVL 2
5 1 EWR BDL 37
6 1 EWR BNA 111
7 1 EWR BOS 430
8 1 EWR BQN 31
9 1 EWR BTV 100
10 1 EWR BUF 119
# ℹ 2,303 more rows
Cela peut permettre d’enchaîner
les opérations groupées. Dans l’exemple suivant, on calcule le pourcentage des trajets pour chaque destination par rapport à tous les trajets du mois :
`summarise()` has grouped output by 'month'. You can override using the
`.groups` argument.
# A tibble: 1,113 × 4
# Groups: month [12]
month dest nb pourcentage
<int> <chr> <int> <dbl>
1 1 ALB 64 0.237
2 1 ATL 1396 5.17
3 1 AUS 169 0.626
4 1 AVL 2 0.00741
5 1 BDL 37 0.137
6 1 BHM 25 0.0926
7 1 BNA 399 1.48
8 1 BOS 1245 4.61
9 1 BQN 93 0.344
10 1 BTV 223 0.826
# ℹ 1,103 more rows
On peut à tout moment dégrouper
un tableau à l’aide de dplyr::ungroup()
. Ce serait par exemple nécessaire, dans l’exemple précédent, si on voulait calculer le pourcentage sur le nombre total de vols plutôt que sur le nombre de vols par mois :
flights |>
group_by(month, dest) |>
summarise(nb = n()) |>
ungroup() |>
mutate(pourcentage = nb / sum(nb) * 100)
`summarise()` has grouped output by 'month'. You can override using the
`.groups` argument.
# A tibble: 1,113 × 4
month dest nb pourcentage
<int> <chr> <int> <dbl>
1 1 ALB 64 0.0190
2 1 ATL 1396 0.415
3 1 AUS 169 0.0502
4 1 AVL 2 0.000594
5 1 BDL 37 0.0110
6 1 BHM 25 0.00742
7 1 BNA 399 0.118
8 1 BOS 1245 0.370
9 1 BQN 93 0.0276
10 1 BTV 223 0.0662
# ℹ 1,103 more rows
À noter que dplyr::count()
, par contre, renvoi un tableau non groupé :
8.4 Cheatsheet
8.5 webin-R
On pourra également se référer au webin-R #04 (manipuler les données avec dplyr) sur YouTube.