0% ont trouvé ce document utile (0 vote)
22 vues20 pages

Cour Datatable1

Le document présente des recommandations pour manipuler des données avec R, en se concentrant sur le package data.table pour les grandes tables de données. Il explique les fonctionnalités de data.table, y compris la syntaxe des opérations, la sélection de lignes et de colonnes, ainsi que le calcul de statistiques. Des exemples pratiques illustrent l'utilisation de data.table par rapport à d'autres packages comme dplyr.

Transféré par

ntln0025
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
22 vues20 pages

Cour Datatable1

Le document présente des recommandations pour manipuler des données avec R, en se concentrant sur le package data.table pour les grandes tables de données. Il explique les fonctionnalités de data.table, y compris la syntaxe des opérations, la sélection de lignes et de colonnes, ainsi que le calcul de statistiques. Des exemples pratiques illustrent l'utilisation de data.table par rapport à d'autres packages comme dplyr.

Transféré par

ntln0025
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd

1.

Choisir son paradigme d’analyse des données avec R


2. 18 Manipuler des données avec [Link]

18 Manipuler des données avec [Link]


18.1 Tâches concernées et recommandations
L’utilisateur souhaite manipuler des données structurées sous forme
de [Link] (sélectionner des variables, sélectionner des observations, créer des variables,
joindre des tables).
Tâche concernée et recommandation

 Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d’un
million d’observations), il est recommandé d’utiliser
les packages tibble, dplyr et tidyr qui sont présentés dans la fiche Manipuler des
données avec le tidyverse;
 Pour des tables de données de grande taille (plus de 1 Go ou plus d’un million
d’observations), il est recommandé d’utiliser soit le package [Link] qui fait l’objet
de la présente fiche, soit les packages arrow et duckdb présentés dans les
fiches Manipuler des données avec arrow et Manipuler des données avec duckdb.

Note
Certains exemples de cette fiche utilisent les données disponibles dans
le package doremifasolData ; vous ne pourrez reproduire ces exemples que si ce package est
installé sur la machine sur laquelle vous travaillez. Si vous ne savez pas si ce package est déjà
installé, consultez la fiche Comment utiliser la documentation utilitR.

18.2 Présentation de [Link]


Ne pas oublier de charger le package avec library([Link]).

18.2.1 Principes structurants

Le package [Link] propose une version améliorée du [Link] de base :


le [Link]. La principale différence visible est que la visualisation d’un
objet [Link] est meilleure que celle d’un [Link] standard : le [Link] indique
automatiquement le type des variables (sous le nom de variable), et donne le nombre total
d’observations de la table.
dt <- [Link](x = c("A", "B", "C"),
y = 1:12,
z = 3:6)
dt
x y z
1: A 1 3
2: B 2 4
3: C 3 5
4: A 4 6
5: B 5 3
6: C 6 4
7: A 7 5
8: B 8 6
9: C 9 3
10: A 10 4
11: B 11 5
12: C 12 6
Note
Il est possible de modifier les options globales de [Link] pour avoir un affichage plus
informatif avec les classes de chaque colonne et l’éventuelle clé de la base (voir plus bas) :
options(
"[Link]" = TRUE,
"[Link]" = TRUE
)
dt
x y z
<char> <int> <int>
1: A 1 3
2: B 2 4
3: C 3 5
4: A 4 6
5: B 5 3
6: C 6 4
7: A 7 5
8: B 8 6
9: C 9 3
10: A 10 4
11: B 11 5
12: C 12 6
options(
"[Link]" = FALSE,
"[Link]" = FALSE
)

La fonction fondamentale de [Link] est l’opérateur [...] (crochets). Lorsqu’on les


applique à un objet [Link] de base, les crochets df[...] servent uniquement à
sélectionner des lignes ou des colonnes. Dans un [Link], les crochets dt[...] permettent
de faire beaucoup plus de choses (quasiment tout, en pratique). En fait, les instructions à
l’intérieur des crochets peuvent être envisagées comme des requêtes SQL mises en forme
différemment.
La forme générale de l’opérateur [...] est la suivante : DT[i, j, by]. Cette grammaire
peut se lire comme ceci : “on part du [Link] DT, on sélectionne certaines lignes avec i,
puis on calcule j pour chaque groupe défini par by. Si on fait un parallèle avec SQL, i correspond
au WHERE, j au SELECT et by au GROUP BY. La fonction [...] présente deux grands avantages :

 Il n’est pas nécessaire d’utiliser le préfixe DT$ pour se référer aux variables à l’intérieur
de [...] ;
 Le code est très concis, ce qui aide à le rendre lisible.
Note
Cette syntaxe compacte est aussi un des atouts fondamentaux de [Link] pour sa
rapidité : [Link] ne manipule que les colonnes mentionnées dans l’opérateur [...], ce qui
réduit le temps de traitement des données.
Voici un exemple simple. A partir des données générées ci-dessus, on veut calculer la moyenne
de y par groupe défini par x, uniquement sur les observations pour lesquelles x est supérieur à 3.
Voici comment on peut réaliser cette opération avec Base R, dplyr et [Link]. Vous
pouvez juger vous-même de la concision du code.
aggregate(
dt[dt[["x"]] > 3]$y,
Base R by = list(dt[dt[["x"]] > 3]$z),
FUN = sum)

dt %>%
dplyr::filter(x > 3) %>%
dplyr dplyr::group_by(z) %>%
dplyr::summarise(sum(y))

[Link] dt[x > 3, sum(y), by = z]

Tip
L’utilisation du package [Link] peut paraître plus déroutante pour les débutants que
l’utilisation de dplyr. Toutefois, l’apprentissage de [Link] est particulièrement
recommandé si vous avez l’intention d’utiliser R avec des données volumineuses
car [Link] est beaucoup plus rapide et puissant que dplyr. Des remarques et conseils sont
présents dans cette fiche pour vous aider à vous familiariser avec la syntaxe de [Link].

18.2.2 Quelles fonctions peut-on utiliser avec un [Link] ?

Les [Link] sont simplement des [Link] particuliers, donc on peut


normalement leur appliquer toutes les méthodes valables pour les [Link]. En
particulier, on peut utiliser avec [Link] toutes les fonctions des packages habituellement
associés à dplyr : stringr pour le maniement de chaînes de caractères, lubridate pour les
colonnes temporelles, forcats pour les colonnes de type factor, etc. Toutefois, il est utile de
vérifier que le package [Link] ne propose pas déjà une fonction adaptée. Par exemple,
plutôt que d’utiliser la fonction str_split_fixed() du package stringr pour séparer une
colonne en fonction d’un caractère, on utilisera tstrsplit() de [Link].

18.2.3 Enchaîner les opérations en [Link]

[Link] Le principe est simple…

Il est facile d’enchaîner des opérations avec [Link] : il suffit d’accoler les
opérateurs []. Votre code [Link] prendra alors la forme suivante : dt[opération 1]
[opération 2][opération 3][...]. Voici un exemple simple, dans lequel on calcule la
moyenne d’une variable par groupe, puis on trie la table.
# En chaînant
ans <- dt[ , .(moyenne = mean(y, [Link] = TRUE)), by = x][order(moyenne)]
ans
x moyenne
1: A 5.5
2: B 6.5
3: C 7.5

[Link] … mais il faut que le code reste lisible…

Le problème avec l’enchaînement d’opérations multiples est qu’on aboutit rapidement à des
lignes de codes extrêmement longues. C’est pourquoi il est préférable de revenir régulièrement
à la ligne, de façon à garder un code qui reste lisible. Il y a évidemment plusieurs façons
d’organiser le code. La seule obligation est que le crochet qui commence une nouvelle opération
doit être accolé au crochet qui termine l’opération précédente (...][...). Voici deux
organisations possibles, à vous de choisir celle qui vous paraît la plus claire et la plus adaptée à
votre travail.
La première organisation enchaîne toutes les opérations en une seule fois :
resultat <-
dt[i = ...,
j = ...,
by = ...
][i = ...,
j = ...,
by = ...
]

La seconde organisation sépare les opérations en utilisant une table intermédiaire


nommée resultat :
resultat <- dt[i = ...,
j = ...,
by = ...
]
resultat <- resultat[i = ...,
j = ...,
by = ...
]

Comme indiqué précédemment, i, j et by ne sont pas forcément présents dans toutes les étapes.
Voici ce que cette organisation du code donne sur un exemple légèrement plus complexe que le
précédent :
dt[ , total := y + z]
resultat <- dt[ ,
.(moyenne = mean(total, [Link] = TRUE)),
by = x
][order(moyenne)]
resultat
x moyenne
1: A 10
2: B 11
3: C 12

[Link] … car on peut facilement faire des erreurs


L’enchaînement des opérations en [Link] est puissant, mais peut aboutir à des
résultats non désirés si on ne fait pas attention. Les exemples de ce paragraphe utilisent la
fonction := ; si vous ne la connaissez pas encore, il est fortement conseillé de lire la section La
fonction d’assignation par référence (ou :=) avant de poursuivre la lecture.
Voici deux exemples d’opérations enchaînées en [Link] dont les codes sont très similaires
et qui aboutissent à des résultats très différents. Le premier exemple ne conserve qu’une partie de
la table dt puis crée une variable, tandis que le second crée une variable avec une valeur non
manquante pour une partie de la table uniquement.
Exemple 1 Exemple 2
Code dt[y > 3][ , newvar := 1] dt[y > 3, newvar := 1]

Partir de dt, conserver uniquement les Partir de dt, créer une nouvelle
observations pour lesquelles x > 3, et variable newvar qui vaut 1 pour les
Signification
créer une nouvelle variable newvar qui observations pour lesquelles x >
vaut 1 partout 3 et NA ailleurs

18.3 Manipuler des tables de données avec [Link]


Nous allons illustrer les fonctions de manipulation de données de [Link] avec les jeux de
données du package doremifasolData.
library(doremifasolData)

18.3.1 Mettre des données dans un [Link]

Il y a principalement deux méthodes pour mettre des données sous forme d’un [Link] :

 la fonction fread() importe un fichier plat comme les .csv (voir la fiche Importer des
fichiers plats (.csv, .tsv, .txt) ;
 Les fonctions setDT() et [Link]() convertissent
un [Link] en [Link].

Dans la suite de cette section, on va illustrer les opérations de base en [Link] avec la base
permanente des équipements (table bpe_ens_2018), qu’on transforme en [Link].
# Charger la base permanente des équipements
bpe_ens_2018 <- doremifasolData::bpe_ens_2018
# Convertir ce [Link] en [Link]
bpe_ens_2018_dt <- [Link](bpe_ens_2018)

18.3.2 Manipuler une seule table avec [Link]

[Link] Sélectionner des lignes

On peut sélectionner des lignes dans un [Link] avec dt[i]. Voici un exemple de code
qui sélectionne les magasins de chaussures (TYPEQU == "B304") dans le premier
arrondissement de Paris (DEPCOM == "75101") dans la table bpe_ens_2018_dt :
selection <- bpe_ens_2018_dt[DEPCOM == "75101" & TYPEQU == "B304"]
Note
Voici une remarque très importante sur le fonctionnement de [Link] : lorsqu’on souhaite
conserver toutes les lignes d’un [Link], il faut laisser vide l’emplacement pour i, sans
oublier la virgule. Par exemple, pour connaître le nombre de lignes de iris_dt, on
écrit : iris_dt[ , .N]. Notez bien l’emplacement vide et la virgule après [.

[Link] Sélectionner des colonnes

On peut sélectionner des colonnes dans un [Link] et renvoyer un [Link] de


plusieurs façons.

 La première consiste à indiquer les colonnes à conserver sous forme de liste. La


notation .() est un alias pour list() qui est pratique et concis dans un
code [Link]. Le code suivant sélectionne le code commune, le type d’équipement
et le nombre d’équipement dans la base permanente des équipements, de deux façons
équivalentes :

bpe_ens_2018_dt[ , list(DEPCOM, TYPEQU, NB_EQUIP)]


bpe_ens_2018_dt[ , .(DEPCOM, TYPEQU, NB_EQUIP)]

 La seconde méthode consiste à utiliser un mot-clé de [Link], .SD qui


signifie Subset of Data. On indique les colonnes qui seront aliasées par .SD avec la
dimension .SDcols.

bpe_ens_2018_dt[ , .SD, .SDcols = c("DEPCOM", "TYPEQU", "NB_EQUIP")]

Note
La seconde méthode peut vous sembler inutilement complexe. C’est vrai dans l’exemple donné
ci-dessus, mais les fonctions .SD et .SDcols s’avèrent très puissantes dans un grand nombre de
situations (notamment quand on veut programmer des fonctions qui font appel à [Link]).

[Link] Trier un [Link]

On peut trier un [Link] avec la fonction order(). Le code suivant trie la BPE selon le
code commune et le type d’équipement.
bpe_ens_2018_dt[order(DEPCOM, TYPEQU)]
REG DEP DEPCOM DCIRIS AN TYPEQU NB_EQUIP
1: 84 01 01001 01001 2018 A401 2
2: 84 01 01001 01001 2018 A404 4
3: 84 01 01001 01001 2018 A504 1
4: 84 01 01001 01001 2018 A507 1
---
1035561: 06 976 97617 97617 2018 F113 4
1035562: 06 976 97617 97617 2018 F114 1
1035563: 06 976 97617 97617 2018 F120 1
1035564: 06 976 97617 97617 2018 F121 3
Il suffit d’ajouter un signe - devant une variable pour trier par ordre décroissant. Le code suivant
trie la BPE par code commune croissant et type d’équipement décroissant.
bpe_ens_2018_dt[order(DEPCOM, -TYPEQU)]
[Link] Calculer des statistiques

La méthode pour sélectionner des colonnes est également valable pour calculer des
statistiques, car [Link] accepte les expressions dans j. Le code suivant calcule le
nombre total d’équipements dans la BPE, sum(NB_EQUIP, [Link] = TRUE) :
bpe_ens_2018_dt[ , .(sum(NB_EQUIP, [Link] = TRUE))]
V1
1: 2504782
Il est possible de calculer plusieurs statistiques à la fois, et de donner des noms aux variables ; il
suffit de séparer les formules par une virgule. Le code suivant calcule le nombre total
d’équipements dans la BPE sum(NB_EQUIP, [Link] = TRUE), et le nombre total de
boulangeries sum(NB_EQUIP * (TYPEQU == "B203"), [Link] = TRUE).
bpe_ens_2018_dt[ ,
.(NB_EQUIP_TOT = sum(NB_EQUIP, [Link] = TRUE),
NB_BOULANG_TOT = sum(NB_EQUIP * (TYPEQU == "B203"), [Link] =
TRUE))]
NB_EQUIP_TOT NB_BOULANG_TOT
1: 2504782 48568
On peut évidemment combiner i et j pour calculer des statistiques sur un sous-ensemble
d’observations. Dans l’exemple suivant, on sélectionne les boulangeries avec i, (TYPEQU ==
"B203"), et on calcule le nombre total d’équipements avec j, sum(NB_EQUIP, [Link] =
TRUE).
bpe_ens_2018_dt[TYPEQU == "B203", .(NB_BOULANG_TOT = sum(NB_EQUIP, [Link] =
TRUE))]
NB_BOULANG_TOT
1: 48568

[Link] Les fonctions statistiques utiles de [Link]

Vous pouvez utiliser toutes les fonctions statistiques de R avec [Link].


Le package [Link] propose par ailleurs des fonctions optimisées qui peuvent vous être
utiles. En voici quelques-unes :
Fonction Opération Exemple
dt[ , .N, by =
.N Nombre d’observations 'group_var']
uniqueN( dt[ , uniqueN(x), by
)
Nombre de valeurs uniques de la variable x = 'group_var']
Remplit les valeurs manquantes d’une variable numérique, par dt[ , nafill(y, fill
nafill
exemple par 123 (pour plus d’options, voir l’aide ?nafill) = 123)]
dt[x %chin% c("a",
%chin% Chaîne de caractères dans la liste "b")]
%between dt[x %between%
%
Valeur entre deux nombres c(5,13)]
Reconnaissance d’une chaîne de caractères (expression dt[departement %like%
%like%
régulière) "^Haute"]
Note
La fonction .N permet de créer facilement des compteurs avec la syntaxe 1:.N ou seq(.N). Par
exemple dt[ , compteur := seq(.N), by = 'x'] permet de créer une
variable compteur qui vaut de 1 à N pour chaque groupe d’observations défini par x.

[Link] Opérations par groupe

Toutes les opérations précédentes peuvent être réalisées par groupe. Il suffit d’ajouter le nom
des variables de groupe dans by (c’est l’équivalent du group_by() du package dplyr).
Lorsqu’il y a plusieurs variables de groupe, on peut écrire l’argument by de deux façons :

 soit by = c("var1", "var2", "var3") (attention aux guillemets) ;


 soit by = .(var1, var2, var3) (attention à la notation .()).

Le code suivant groupe les données de la BPE par département, by = .(DEP), puis calcule le
nombre total d’équipements, sum(NB_EQUIP, [Link] = TRUE) et le nombre total de
boulangeries, sum(NB_EQUIP * (TYPEQU == "B203"), [Link] = TRUE).
bpe_ens_2018_dt[ ,
.(NB_EQUIP_TOT = sum(NB_EQUIP, [Link] = TRUE),
NB_BOULANG_TOT = sum(NB_EQUIP * (TYPEQU == "B203"), [Link] =
TRUE)),
by = .(DEP)]
DEP NB_EQUIP_TOT NB_BOULANG_TOT
1: 01 21394 401
2: 02 15534 339
3: 03 12216 299
4: 04 8901 185
---
98: 972 19068 370
99: 973 7852 98
100: 974 30767 646
101: 976 7353 101
Note
L’argument by fonctionne également avec l’opérateur :=. Vous pouvez en apprendre davantage
sur l’usage de cet opérateur dans la partie La fonction d’assignation par référence (ou :=).

18.3.3 Joindre des tables avec [Link]

Pour joindre des données, [Link] propose une fonction merge() plus rapide que la
fonction de base. La syntaxe générale est z <- merge(x, y, [options]). Voici une liste des
principales options (les autres options sont consultables avec ?[Link]::merge) :
Option Signification
Joindre sur la variable var_jointure (présente dans x et
by = var_jointure
dans y)
by.x = "identx", by.y =
"identy"
Joindre sur la condition identx == identy
all.x = TRUE Left join (garder toutes les lignes de x)
all.y = TRUE Right join (garder toutes les lignes de y)
Option Signification
all = TRUE Full join (garder toutes les lignes de x et de y)
Enfin, il est possible de réaliser des jointures plus sophistiquées avec [Link]. Ces méthodes
sont présentées dans la vignette sur le sujet.

18.3.4 Indexer une table avec [Link]

L’indexation est une fonctionnalité très puissante pour accélérer les opérations sur les
lignes (filtres, jointures, etc.) en [Link]. Pour indexer une table il faut déclarer les
variables faisant office de clé (appelées key). C’est possible de la manière
suivante : setkey(dt, a) ou setkeyv(dt, "a"). Le [Link] sera réordonné en fonction
de cette variable et l’algorithme de recherche sur les lignes sera ainsi beaucoup plus efficace.
Lorsqu’il y a plusieurs variables-clé, on écrit setkey(dt, a, b) ou setkeyv(dt,
c("a","b")).
Pour savoir si un [Link] est déjà indexé, on peut exécuter la commande key(dt) qui
renvoie le nom des clés s’il y en a, et NULL sinon.
Tip
L’exécution de la fonction [Link]::setkey() peut prendre un peu de temps (parfois
quelques minutes sur une table de plus de 10 millions de lignes), car [Link] trie toute la
table en fonction des variables-clé. Toutefois, c’est une étape vraiment utile car elle accélère
considérablement les opérations ultérieures sur les lignes. Il est vivement recommandé de
l’utiliser si une ou plusieurs variables vont régulièrement servir à filtrer ou combiner des données.
Pour aller plus loin, voir cette vignette.

18.3.5 Réorganiser les données en [Link]

Le package [Link] permet de réorganiser facilement une table de données avec les
fonctions dcast() et melt(). La fonction melt() réorganise les données dans un format long.
La fonction dcast() réorganise les données dans un format wide.
melt() dcast()
Réorganiser les données dans un format long Réorganise les données dans un format wide

[Link] melt : transformer des colonnes en lignes

La fonction melt() réorganise les donnée dans un format long. Elle prend les arguments suivants
:
 data : les données ;
 [Link] : les variables qui identifient les lignes de table d’arrivée ; elles restent
inchangées lors de l’utilisation de melt() ;
 [Link] : les variables qui sont transposées ;
 [Link] : le nom de la nouvelle colonne qui contient le nom des variables
transposées ;
 [Link] : le nom de la nouvelle colonne qui contient la valeur des variables
transposées.

Pour illustrer l’usage de cette fonction, nous allons utiliser les données du répertoire Filosofi
2016 agrégées au niveau des EPCI (table filosofi_epci_2016), et disponibles dans le
package doremifasolData. On convertit cette table en [Link] et on conserve uniquement
certaines variables.
# Charger la table de Filosofi
filosofi_epci_2016 <- doremifasolData::filosofi_epci_2016
# Convertir la table en [Link]
filosofi_epci_2016_dt <- [Link](filosofi_epci_2016)
# Sélectionner des colonnes
filosofi_epci_2016_dt <-
filosofi_epci_2016_dt[, .(CODGEO, TP6016, TP60AGE116, TP60AGE216,
TP60AGE316, TP60AGE416, TP60AGE516, TP60AGE616)]

Nous allons restructurer cette table pour obtenir une nouvelle table, avec une observation par
EPCI et par tranche d’âge. Voici le code qui permet d’obtenir cette table : on indique
dans [Link] le nom des colonnes qui seront transposées, le nom des colonnes
transposées sera indiqué dans la nouvelle colonne “tranche_age” ([Link] =
"tranche_age") et les valeurs des colonnes transposées seront stockées dans la colonne
“taux_pauvrete” ([Link] = "taux_pauvrete").
donnees_pauvrete_long <-
melt(data = filosofi_epci_2016_dt,
[Link] = c("CODGEO"),
[Link] = c("TP6016", "TP60AGE116", "TP60AGE216",
"TP60AGE316", "TP60AGE416", "TP60AGE516",
"TP60AGE616"),
[Link] = "tranche_age",
[Link] = "taux_pauvrete"
)
donnees_pauvrete_long
CODGEO tranche_age taux_pauvrete
1: 200000172 TP6016 8.8
2: 200000438 TP6016 8.0
3: 200000545 TP6016 23.7
4: 200000628 TP6016 20.1
---
8705: 249740085 TP60AGE616 41.5
8706: 249740093 TP60AGE616 43.4
8707: 249740101 TP60AGE616 39.8
8708: 249740119 TP60AGE616 31.7
Tip
Il est recommandé de travailler avec des données en format long plutôt qu’en format wide,
notamment lorsque vous voulez faire des graphiques. En effet, le package de visualisation
graphique ggplot2 est optimisé pour manipuler des données en format long (voir la fiche [Faire
des graphiques avec ggplot2]). Ce conseil est particulièrement important si vous voulez
représenter un graphique avec des groupes : il est préférable que les groupes soient empilés
(format long) plutôt que juxtaposés (format wide), car le code est plus rapide et facile à écrire.

[Link] dcast : transformer des lignes en colonnes

La fonction dcast() réorganise les donnée dans un format large. Elle prend les arguments
suivants :

 data : les données ;


 formula : une formule de la forme var_ligne ~ var_colonne qui définit la structure
de la nouvelle table ;
o s’il y a plusieurs variables, la formule prend la forme var1 + var2 ~ var3 ;
o dcast() conserve une ligne par valeur de la partie gauche, et crée (au moins) une
colonne par valeur de la partie droite ;
 [Link] : une liste contenant la ou les fonction(s) utilisées pour agréger les
données le cas échéant ; exemple : list(mean, sum, sd) ;
 [Link] : un vecteur contenant le nom de la ou des colonne(s) dont les valeurs vont
être transposées ; exemple : c("var1", "var2").

Dans l’exemple qui suit, on réorganise la table bpe_ens_2018_dt de façon à obtenir une table
qui contient une ligne par type d’équipement et une colonne par région (TYPEQU ~ REG). Ces
colonnes vont contenir la somme ([Link] = sum) du nombre d’équipements
([Link] = "NB_EQUIP").
bpe_ens_2018_wide <- dcast(bpe_ens_2018_dt,
TYPEQU ~ REG,
[Link] = "NB_EQUIP",
[Link] = sum)
head(bpe_ens_2018_wide)
TYPEQU 01 02 03 04 06 11 24 27 28 32 44 52 53 75 76 84 93 94
1: A101 2 2 1 7 0 191 28 23 54 127 80 15 20 66 55 69 34 3
2: A104 20 21 16 28 5 91 153 230 183 214 319 173 157 407 406 423 179 39
3: A105 1 1 1 1 1 2 2 2 2 2 4 1 1 5 3 4 1 1
4: A106 2 1 2 2 1 10 7 12 10 17 17 8 8 19 19 21 11 2
5: A107 2 1 1 4 1 60 9 19 15 26 30 11 12 28 26 34 23 2
6: A108 2 1 1 2 1 19 9 13 13 25 21 8 10 21 20 28 14 2
Il est possible d’utiliser dcast() avec plusieurs variables à transposer et plusieurs fonctions
pour transposer. Dans l’exemple qui suit, on obtient une ligne par type d’équipement, et une
colonne par région et par fonction d’agrégation (mean et sum).
bpe_ens_2018_wide2 <- dcast(bpe_ens_2018_dt,
TYPEQU ~ REG,
[Link] = "NB_EQUIP",
[Link] = list(sum, mean))
bpe_ens_2018_wide2
TYPEQU NB_EQUIP_sum_01 NB_EQUIP_sum_02 NB_EQUIP_sum_03 NB_EQUIP_sum_04
1: A101 2 2 1 7
2: A104 20 21 16 28
3: A105 1 1 1 1
4: A106 2 1 2 2
---
183: G101 105 79 48 136
184: G102 49 49 29 112
185: G103 0 0 0 0
186: G104 110 104 46 98
NB_EQUIP_sum_06 NB_EQUIP_sum_11 NB_EQUIP_sum_24 NB_EQUIP_sum_27
1: 0 191 28 23
2: 5 91 153 230
3: 1 2 2 2
4: 1 10 7 12
---
183: 20 3351 213 256
184: 11 2478 670 890
185: 0 96 238 330
186: 6 2993 293 339
NB_EQUIP_sum_28 NB_EQUIP_sum_32 NB_EQUIP_sum_44 NB_EQUIP_sum_52
1: 54 127 80 15
2: 183 214 319 173
3: 2 2 4 1
4: 10 17 17 8
---
183: 272 495 593 376
184: 845 698 1318 762
185: 378 521 368 646
186: 401 354 533 330
NB_EQUIP_sum_53 NB_EQUIP_sum_75 NB_EQUIP_sum_76 NB_EQUIP_sum_84
1: 20 66 55 69
2: 157 407 406 423
3: 1 5 3 4
4: 8 19 19 21
---
183: 345 720 786 1166
184: 943 1908 1982 2797
185: 751 1408 1437 1265
186: 374 926 932 1099
NB_EQUIP_sum_93 NB_EQUIP_sum_94 NB_EQUIP_mean_01 NB_EQUIP_mean_02
1: 34 3 1.000000 1.000000
2: 179 39 1.000000 1.000000
3: 1 1 1.000000 1.000000
4: 11 2 1.000000 1.000000
---
183: 1016 120 2.282609 1.975000
184: 2111 438 2.450000 2.130435
185: 718 187 NaN NaN
186: 876 182 1.718750 1.575758
NB_EQUIP_mean_03 NB_EQUIP_mean_04 NB_EQUIP_mean_06 NB_EQUIP_mean_11
1: 1.000000 1.000000 NaN 1.091429
2: 1.000000 1.000000 1.000000 1.000000
3: 1.000000 1.000000 1.000000 1.000000
4: 1.000000 1.000000 1.000000 1.000000
---
183: 1.714286 1.837838 5.000000 2.080074
184: 1.318182 2.036364 1.833333 2.250681
185: NaN NaN NaN 1.103448
186: 1.533333 1.400000 1.500000 1.780488
NB_EQUIP_mean_24 NB_EQUIP_mean_27 NB_EQUIP_mean_28 NB_EQUIP_mean_32
1: 1.037037 1.000000 1.018868 1.058333
2: 1.000000 1.004367 1.000000 1.014218
3: 1.000000 1.000000 1.000000 1.000000
4: 1.000000 1.000000 1.000000 1.000000
---
183: 1.601504 1.422222 1.511111 1.633663
184: 1.763158 1.666667 1.978923 1.681928
185: 1.048458 1.103679 1.330986 1.527859
186: 1.140078 1.232727 1.297735 1.156863
NB_EQUIP_mean_44 NB_EQUIP_mean_52 NB_EQUIP_mean_53 NB_EQUIP_mean_75
1: 1.025641 1.000000 1.000000 1.157895
2: 1.009494 1.005814 1.000000 1.007426
3: 1.000000 1.000000 1.000000 1.000000
4: 1.000000 1.000000 1.000000 1.000000
---
183: 1.694286 1.748837 1.674757 1.578947
184: 1.734211 1.836145 2.063457 1.927273
185: 1.153605 2.044304 1.891688 1.733990
186: 1.230947 1.274131 1.307692 1.293296
NB_EQUIP_mean_76 NB_EQUIP_mean_84 NB_EQUIP_mean_93 NB_EQUIP_mean_94
1: 1.145833 1.029851 1.000000 1.000000
2: 1.015000 1.011962 1.028736 1.083333
3: 1.000000 1.000000 1.000000 1.000000
4: 1.000000 1.000000 1.000000 1.000000
---
183: 1.526214 1.707174 1.785589 2.000000
184: 2.045408 2.109351 2.507126 3.369231
185: 1.600223 1.408686 1.681499 2.101124
186: 1.226316 1.345165 1.364486 1.857143
Tip
 La fonction dcast() crée une colonne par valeur des variables utilisées dans la partie
droite de la formule. Il faut donc faire attention à ce que ces variables aient un
nombre limité de valeurs, pour ne pas obtenir une table extrêmement large. On peut
éventuellement discrétiser les variables continues, ou regrouper les modalités avant
d’utiliser dcast().
 On peut obtenir des noms de colonnes peu significatifs lorsqu’on utilise dcast() avec
une fonction d’agrégation. Il est conseillé de modifier légèrement la partie droite de la
formule pour obtenir des noms plus significatifs. Voici un exemple où on ajoute le
préfixe resultat_region :
 bpe_ens_2018_wide2 <- dcast(bpe_ens_2018_dt,
 TYPEQU ~ paste0("resultat_region",REG),
 [Link] = "NB_EQUIP",
 [Link] = sum)
head(bpe_ens_2018_wide2)
TYPEQU resultat_region01 resultat_region02 resultat_region03
1: A101 2 2 1
2: A104 20 21 16
3: A105 1 1 1
4: A106 2 1 2
5: A107 2 1 1
6: A108 2 1 1
resultat_region04 resultat_region06 resultat_region11
resultat_region24
1: 7 0 191
28
2: 28 5 91
153
3: 1 1 2
2
4: 2 1 10
7
5: 4 1 60
9
6: 2 1 19
9
resultat_region27 resultat_region28 resultat_region32
resultat_region44
1: 23 54 127
80
2: 230 183 214
319
3: 2 2 2
4
4: 12 10 17
17
5: 19 15 26
30
6: 13 13 25
21
resultat_region52 resultat_region53 resultat_region75
resultat_region76
1: 15 20 66
55
2: 173 157 407
406
3: 1 1 5
3
4: 8 8 19
19
5: 11 12 28
26
6: 8 10 21
20
resultat_region84 resultat_region93 resultat_region94
1: 69 34 3
2: 423 179 39
3: 4 1 1
4: 21 11 2
5: 34 23 2
6: 28 14 2
Note
Il est conseillé de bien réfléchir avant de restructurer des données en format wide, et de ne
le faire que lorsque cela paraît indispensable. En effet, s’il est tentant de restructurer les
données sous format wide car ce format peut paraître plus intuitif, il est généralement plus simple
et plus rigoureux de traiter les données en format long. Ceci dit, il existe des situations dans
lesquelles il est indiqué de restructurer les données en format wide. Voici deux exemples :

 produire un tableau synthétique de résultats, prêt à être diffusé, avec quelques colonnes
donnant des indicateurs par catégorie (exemple : la
table filosofi_epci_2016 du package doremifasolData) ;
 produire une table avec une colonne par année, de façon à calculer facilement un taux
d’évolution entre deux dates.

18.4 La fonction d’assignation par référence (ou :=)


Jusqu’à présent, nous avons manipulé un [Link] existant, mais nous ne lui avons pas ajouté
de nouvelles colonnes. Pour ce faire, nous allons utiliser la fonction := qui s’appelle “assignation
par référence” et qui peut également s’appeler comme une fonction `:=`(), prenant ses
arguments entre parenthèses. Voici comment on crée une nouvelle colonne
dans bpe_ens_2018_dt :
bpe_ens_2018_dt[ , nouvelle_colonne := NB_EQUIP * 10]
head(bpe_ens_2018_dt)
REG DEP DEPCOM DCIRIS AN TYPEQU NB_EQUIP nouvelle_colonne
1: 84 01 01001 01001 2018 A401 2 20
2: 84 01 01001 01001 2018 A404 4 40
3: 84 01 01001 01001 2018 A504 1 10
4: 84 01 01001 01001 2018 A507 1 10
5: 84 01 01001 01001 2018 B203 1 10
6: 84 01 01001 01001 2018 C104 1 10

18.4.1 La spécificité de [Link] : la modification par référence

A première vue, on peut penser que la fonction := est l’équivalent de la


fonction dplyr::mutate() dans la grammaire [Link]. C’est vrai dans la mesure où elle
permet de faire des choses similaires, mais il faut garder en tête que son fonctionnement est
complètement différent de celui de dplyr::mutate(). En effet, la grande spécificité
de [Link] par rapport à dplyr est que l’utilisation de la fonction := modifie
directement la table de données, car [Link] fonctionne sur le principe de la modification
par référence (voir ce lien pour plus de détails). Cela signifie en pratique qu’il ne faut pas
réassigner l’objet lorsqu’on modifie une de ses colonnes. C’est ce comportement qui permet
à [Link] d’être très rapide et très économe en mémoire vive, rendant son usage approprié
pour des données volumineuses.
Pour créer une colonne, on écrit donc directement dt[ , nouvelle_colonne :=
une_formule] et non dt <- dt[ , nouvelle_colonne := une_formule]. Voici un
exemple qui compare dplyr et [Link] :
Package Code Commentaire
bpe_ens_2018 <-
bpe_ens_2018 %>% Il faut utiliser une assignation (<-) pour
dplyr dplyr::mutate(nouvelle_colonne =
NB_EQUIP * 10)
modifier la table.
[Link] bpe_ens_2018_dt[ , nouvelle_colonne Il ne faut pas d’assignation pour modifier
e := NB_EQUIP * 10]
la table, qui est modifiée par référence.

18.4.2 Les usages de :=

On peut se servir de la fonction := de multiples façons, et avec plusieurs notations.

[Link] Créer plusieurs variables à la fois

Voici comment créer plusieurs variables à la fois avec :=, en utilisant une notation vectorielle :
bpe_ens_2018_dt[ , c("nouvelle_colonne1", "nouvelle_colonne2") :=
list(NB_EQUIP * 2, NB_EQUIP + 3)]

On peut faire exactement la même chose en utilisant la notation `:=`(). Voici le même exemple
écrit avec `:=`().
bpe_ens_2018_dt[ , `:=`(nouvelle_colonne1 = NB_EQUIP * 2,
nouvelle_colonne2 = NB_EQUIP + 3)]

Note
Si vous utilisez la notation`:=`(), alors il faut utiliser uniquement = à l’intérieur des parenthèses
pour créer ou modifier des variables, et non :=. Par exemple,
dt[ , `:=`(var1 = "Hello", var2 = "world")]

[Link] Supprimer une colonne

On peut facilement supprimer une colonne en lui assignant la valeur NULL (c’est hyper rapide !).
Voici un exemple :
bpe_ens_2018_dt[ , NB_EQUIP := NULL]

[Link] Faire un remplacement conditionnel

La fonction := peut être utilisée pour modifier une colonne pour certaines lignes seulement, en
fonction d’une condition logique. C’est beaucoup plus efficace qu’un
terme dplyr::if_else() ou dplyr::case_when(). Imaginons qu’on veuille créer une
colonne EQUIP_HORS_CHAUSS égale au nombre d’équipements (NB_EQUIP) sauf pour les lignes
correspondantes à des magasins de chaussures (TYPEQU == "B304") où elle vaut NA. Dans ce
cas, le code dplyr serait :
bpe_ens_2018 %>%
dplyr::mutate(NB_EQUIP_HORS_CHAUSS = dplyr::case_when(
TYPEQU == "B304" ~ NA_real_,
TRUE ~ NB_EQUIP)
)

Deux alternatives existent en [Link] nécessitant toutes deux beaucoup moins de mémoire
vive :
bpe_ens_2018_dt[ , NB_EQUIP_HORS_CHAUSS := NB_EQUIP
][TYPEQU == "B304", NB_EQUIP_HORS_CHAUSS := NA_real_]

ou bien en utilisant la fonction [Link]::fcase dont le fonctionnement ressemble à celui


de dplyr::case_when :
bpe_ens_2018_dt[ , NB_EQUIP_HORS_CHAUSS := [Link]::fcase(TYPEQU == "B304",
NA_real_,
TYPEQU != "B304", NB_EQUIP)
]

18.4.3 Attention en utilisant :=

L’utilisation de la fonction := est déroutante lorsqu’on découvre [Link]. Voici trois


remarques qui vous feront gagner du temps :
 Vous pouvez faire appel à d’autres fonctions à l’intérieur de la fonction :=. Par
exemple, si on veut mettre la variable name en minuscules, on peut utiliser la
fonction tolower(). On écrit alors :
dt[ , name_minuscule := tolower(name)]

 Lorsque l’on crée plusieurs variables avec la fonction :=, elles sont créées en même
temps. On ne peut donc pas faire appel dans une formule à une variable qu’on crée
dans le même appel à la fonction :=. Par exemple, le code suivant ne fonctionne pas :
 bpe_ens_2018_dt[ , `:=`(nouvelle_colonne1 = NB_EQUIP * 2,
nouvelle_colonne2 = nouvelle_colonne1 + 3)]

En effet, au moment où la fonction := est exécutée, la


colonne nouvelle_colonne1 n’existe pas encore, donc la
formule nouvelle_colonne2 = nouvelle_colonne1 + 3 n’a pas encore de sens. Si
vous créez des variables en chaîne, il faut décomposer l’opération en plusieurs étapes
enchaînées. Voici le code qui permet de créer les deux colonnes à la suite :
bpe_ens_2018_dt[ , nouvelle_colonne1 := NB_EQUIP * 2
][ , nouvelle_colonne2 := nouvelle_colonne1 + 3]

 Un mauvais usage de la fonction := peut vous amener à écraser par erreur vos
données. En effet, si vous exécuter par erreur la commande dt[ ,
ma_variable_importante := 0], vous écrasez la
variable ma_variable_importante. Vous devez alors recharger vos données… Il faut
donc bien réfléchir à ce que vous voulez faire avant de remplacer ou modifier une variable
existante avec la fonction :=. Si vous modifiez un [Link] dans une fonction, un
filet de sécurité consiste à d’abord copier le [Link] initial et ainsi faire les
modifications sur le nouvel objet, de la manière suivante :
 dt_copy <- [Link]::copy(dt)
dt_copy[, ma_variable_importante := "Nouvelle valeur"]

18.5 Programmer des fonctions avec [Link]


Une des forces de [Link] est qu’il est relativement simple d’utiliser ce package dans des
fonctions. Pour illustrer l’usage des fonctions, nous allons utiliser la
table filosofi_com_2016 disponible dans le package doremifasolData. Cette table donne
des informations sur les revenus des ménages au niveau communal. Nous créons une variable
donnant le numéro du département (departement) en extrayant les deux premiers caractères du
code commune (CODGEO) avec la fonction str_sub du package stringr (vous pouvez consulter
la fiche [Manipuler des données textuelles pour en apprendre davantage sur stringr]). Enfin,
nous utilisons la fonction .SD pour sélectionner uniquement quelques variables.
# Charger la table de données et la transformer en [Link]
filosofi_com_2016_dt <- [Link](doremifasolData::filosofi_com_2016)
# Créer une variable donnant le département
filosofi_com_2016_dt[, departement := stringr::str_sub(CODGEO, start = 1L, end
= 2L)]
# Supprimer les départements d'outre-mer
filosofi_com_2016_dt <- filosofi_com_2016_dt[departement != "97"]
# Alléger la table en ne conservant que quelques variables
filosofi_com_2016_dt <-
filosofi_com_2016_dt[, .SD, .SDcols = c("departement", "CODGEO",
"NBMENFISC16",
"NBPERSMENFISC16")]

18.5.1 Utiliser .SD et lapply

Le mot clé .SD (Subset of Data) permet d’appliquer la même opération sur plusieurs colonnes.
Les colonnes auxquelles l’opération s’applique sont contrôlées par l’argument .SDcols (par
défaut, toutes les colonnes sont traitées). Le mot clé .SD est régulièrement utilisé en conjonction
avec la fonction lapply. Cette syntaxe, très puissante, permet également d’avoir des codes
assez compacts, ce qui les rend plus lisible.
Un usage classique de ce duo lapply+.SD consiste à écrire des fonctions de statistiques
descriptives. Par exemple, imaginons qu’on souhaite calculer la moyenne, l’écart-type et les
quantiles (P25, P50 et P75) de nombreuses colonnes. On peut alors définir la fonction suivante :
mes_statistiques <-
function(x) return(c(mean(x, [Link] = TRUE),
sd(x, [Link] = TRUE),
quantile(x, probs = c(.25,.5,.75), [Link] = TRUE)))

Voici comment on peut appliquer cette fonction aux colonnes NBMENFISC16 (nombre de
ménages fiscaux) et NBPERSMENFISC16 (nombre de personnes dans les ménages fiscaux) de la
table filosofi_com_2016_dt :
data_agregee <-
filosofi_com_2016_dt[ ,
lapply(.SD, mes_statistiques),
.SDcols = c("NBMENFISC16", "NBPERSMENFISC16")]
data_agregee[, 'stat' := c("moyenne","écart-type","P25","P50","P75")]
data_agregee
NBMENFISC16 NBPERSMENFISC16 stat
1: 916.3269 2097.18 moyenne
2: 7382.4628 15245.60 écart-type
3: 105.0000 250.50 P25
4: 218.0000 527.00 P50
5: 526.0000 1278.25 P75
Il est également très simple d’effectuer des calculs par groupe avec la
méthode lapply+.SD. On peut par facilement adapter le code précédent pour calculer des
statistiques descriptives par département (variable departement).
data_agregee <-
filosofi_com_2016_dt[ ,
lapply(.SD, mes_statistiques),
by = departement,
.SDcols = c("NBMENFISC16", "NBPERSMENFISC16")]
data_agregee[, 'stat' := c("moyenne","écart-type","P25","P50","P75"), by =
departement]
data_agregee

18.5.2 Définir des fonctions modifiant un [Link]

Il est très facile d’écrire avec [Link] des fonctions génériques faisant appel à des noms
de variables en arguments. Pour déclarer à [Link] qu’un nom fait référence à une
colonne, la manière la plus simple est d’utiliser la fonction get. Dans l’exemple suivant, on
définit la fonction creation_var qui crée dans la table data une nouvelle variable (dont le nom
est l’argument nouveau_nom) égale à une autre variable incrémentée (dont le nom est
l’argument nom_variable) de 1. L’utilisation de la fonction get permet d’indiquer
à [Link] que la chaîne de caractères nom_variable désigne une colonne de la table data.
creation_var <- function(data, nom_variable, nouveau_nom){
data[, c(nouveau_nom) := get(nom_variable) + 1]
}
head(creation_var(filosofi_com_2016_dt,
nom_variable = "NBMENFISC16",
nouveau_nom = "nouvelle_variable"), 2)
departement CODGEO NBMENFISC16 NBPERSMENFISC16 nouvelle_variable
1: 01 01001 313 795.5 314
2: 01 01002 101 248.0 102
c(nouveau_nom) permet de s’assurer que [Link] crée une nouvelle colonne dont le nom
est défini en argument (et qui ne s’appelle donc pas nouveau_nom).
Note
La version 1.14.1 de [Link] (encore en développement) apporte une syntaxe améliorée dans
ce cas et considère l’utilisation de get comme désuète. Le [...] admet un nouvel
argument env à qui on donne tous les remplacements que l’on souhaite. L’exemple devient :
creation_var <- function(data, nom_variable, nouveau_nom){
data[, nouveau_nom := nom_variable + 1,
env = list(nouveau_nom = nouveau_nom, nom_variable = nom_variable)]
}
head(creation_var(filosofi_com_2016_dt,
nom_variable = "NBMENFISC16",
nouveau_nom = "nouvelle_variable"), 2)
L’avantage c’est qu’on peut effectuer de tels remplacements dans i (dimension ligne) et qu’on
peut même remplacer des fonctions :
creation_var <- function(data, nom_variable, nouveau_nom, fonction){
data[, nouveau_nom := fonction(nom_variable),
env = list(nouveau_nom = nouveau_nom, nom_variable = nom_variable,
fonction= fonction)]
head(creation_var(filosofi_com_2016_dt,
nom_variable = "NBMENFISC16",
nouveau_nom = "nouvelle_variable",
fonction = "sqrt"), 2)
}
Tip
Lorsqu’on définit des fonctions pour effectuer des traitements génériques, une précaution est
nécessaire pour ne pas modifier les données en entrée de la fonction si l’opérateur := est utilisée.
Il est recommandé dans ce cas de créer une copie du dataframe en entrée
([Link]::copy(df)) et d’effectuer les traitements sur cette copie.

18.6 Pour en savoir plus


 la documentation officielle de [Link] (en anglais) ;
 les vignettes de [Link] :
o Introduction à [Link] (en anglais) ;
o Modification par référence (en anglais) ;
o la foire aux questions de [Link] (en anglais) ;
 une cheatsheet sur [Link] (en anglais) ;
 une introduction à l’utilisation de l’opérateur [...] (en français) ;
 Ce cours complet sur [Link] (en français).
 Cette présentation des fonctionnalités du package (en français) ;
 Ce post sur les fonctions utilisant [Link].

17 Manipuler des données avec le tidyverse


19 Manipuler des données avec `arrow`' class='pagination-link'
href='/03_fiches_thematiques/fiche_arrow'>19 Manipuler des données avec arrow
This book was built with Quarto.

 Code source

Vous aimerez peut-être aussi