L’objectif est de passer en revue les différentes fonctions de la la librairie dplyr

library(dplyr)

permettant par exemple de

Ces différentes opérations sont appliquées sur le jeu de données flights de la librairie nycflights13

library(nycflights13)
flights

Le jeu de données flights est un tibble une variante de data frame optimisé pour l’usage des fonction de tidyverse.

library(tibble)

Nous allons nous focaliser sur les cinq fonctions clés de la librairie dplyr, à savoir

Ces fonctions s’utilisent en parallèle de la fonction group_by() permettant le traitement par groupe d’observations. Elles prennent toujours comme premier argument le data frame sur lequel on travaille.

Sélectionner des observations avec filter()

# Sélection des vols du 1er Janvier. 
filter(flights, month == 1 & day == 1)
# Sélection des vols de novembre et de décembre
filter(flights, month == 11 | month == 12)
# Autre alternative avec l'opérateur %in%
filter(flights, month %in% c(11, 12))

Trier les observations avec arrange()

# Trier par année, mois jours
arrange(flights, year, month, day)

On utilise la fonction desc() pour trier par ordre décroissant.

# Trie en fonction du retard par ordre décroissant
arrange(flights, desc(dep_delay))

Les valeurs manquantes sont toujours placées à la fin.

Sélectionner des variable avec select()

# Conserve toutes les variables entre year et day (inclus)
select(flights, year:day)
# Sélectionne toute les variables exceptées celles entre year et day (inclus)
select(flights, -(year:day))

La sélection des variables est facilitée par l’utilisation des fonctions suivantes

Créer des variables avec mutate()

# Table flights_sml contenant une sélection de variables. 
flights_sml <- select(flights, 
  year:day, 
  ends_with("delay"), 
  distance, 
  air_time
)
# Calcul du rattrapage de retard et de la vitesse
mutate(flights_sml,
  during_flight_delay = arr_delay - dep_delay,
  speed = distance / air_time * 60
)

On peut aussi faire référence aux variables que l’on vinet de créer

mutate(flights_sml,
  during_flight_delay = arr_delay - dep_delay,
  hours = air_time / 60,
  during_flight_delay = during_flight_delay / hours
)

En utilisant la fonction transmute, on ne conserve que les variables nouvellement créées

transmute(flights,
  during_flight_delay = arr_delay - dep_delay,
  hours = air_time / 60,
  gain_per_hour = during_flight_delay / hours
)

Parmi les fonctions utiles pour la création de variable, on compte les fonctions décalages lag() et lead()

x <- 1:10
lag(x)
##  [1] NA  1  2  3  4  5  6  7  8  9
lead(x)
##  [1]  2  3  4  5  6  7  8  9 10 NA

Ces fonctions sont utiles pour calculer des variations successives avec x-lag(x) ou détecter un changement de valeur x != lag(x) et les fonctions cumulatives cumsum(), cumprod(), cummin(), cummax() et cummean()

# Sommes cumulées
cumsum(x)
##  [1]  1  3  6 10 15 21 28 36 45 55
# Moyennes mobiles
cummean(x)
##  [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5

Résumés statistiques avec summarise() et group_by()

La fonction summarize() réduit le data frame à une seule ligne

summarise(flights, delay = mean(dep_delay, na.rm = TRUE))

Elle n’est pas très utile à moins d’être combinée avec group_by(). On peut ainsi obtenir la moyenne des retards au départ des vols pour chaque jour

by_day <- group_by(flights, year, month, day)
summarise(by_day, delay  = mean(dep_delay, na.rm = T))

Combiner des opérations à l’aide d’un pipe

Nous souhaitons étudier la relation entre la distance et le retard.

library(ggplot2)
# On regroupe les vols par destinations
by_dest <- group_by(flights, dest)

# On calcule une distance moyenne et un retard moyen par destination
# La variable count = n() permet de conserver le nombre d'observations placées dans chaque groupe. 
delay <- summarise(by_dest,
  count = n(),
  dist = mean(distance, na.rm = TRUE),
  delay = mean(arr_delay, na.rm = TRUE)
)

# Nuage de point pondéré par la variable count() sur lequel on ajoute une courbe de tendance polynomial 
ggplot(data = delay, mapping = aes(x = dist, y = delay)) +
  geom_point(aes(size = count)) +
  geom_smooth(method = loess)
## Warning: Removed 1 rows containing non-finite values (stat_smooth).
## Warning: Removed 1 rows containing missing values (geom_point).

On observe une tendance décroissante qui tend à conjecturer qu’une longue distance donne au pilote plus de marge pour rattraper le retard du vol. Une dernière opération peut être effectuée afin par exemple d’enlever l’aeroport d’Honolulu et les aéroports avec très peu de vol qui semble être souvent des valeurs marginales.

#On enlève les vols vers Honolulu et les destination avec moins de 20 vols
delay <- filter(delay, count > 20, dest != "HNL")
# On refait le même graphique que précédemment
ggplot(data = delay, mapping = aes(x = dist, y = delay)) +
  geom_point(aes(size = count)) +
  geom_smooth(se = FALSE)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

Le pipe %>% permet de ne pas créer des data frames intermédiaires et améliore la lisibilité du code

delays <- flights %>% 
  group_by(dest) %>% 
  summarise(
    count = n(),
    dist = mean(distance, na.rm = TRUE),
    delay = mean(arr_delay, na.rm = TRUE)
  ) %>% 
  filter(count > 20, dest != "HNL")

Fusion de deux tables avec left_join()

Une fusion de deux data frames permet la création d’un nouveau data frame contenant plus de variables. La combinaison des deux data frames initiaux est possible du fait de la présence d’une ou plusieurs variables en commun dans les deux data frames. La librairie nycflights13 contient plusieurs jeu de données.

data(flights)
data(airports)
data(airlines)

la variable carrier dans la table flights contient indique la compagnie ayant opéré le vol. 

flights %>% select(carrier)

On souhaite récupérer à l’aide cette information le nom complet de la compagnie aérienne qui est renseigné dans le data frame airlines.

airlines

Il est naturel de vouloir associer les deux data frames pour par exemple ajouter l’information name dans le data frame flights, on utilise pour cela la fonction left_join.

left_join(flights, airlines) %>% select(month, day, carrier, name)
## Joining, by = "carrier"

Dans cet exemple aucun preprocessing n’est nécessaire. La table airports contient des informations relatives aux aéroports

data("airports")
airports

La variable faa contient le code de l’aéroport, cette information est aussi présente dans la table flights avec la variable origin correspondant à l’aéroport de départ et dest pour l’aéroport d’arrivée.

flights %>% select(day, month, origin, dest)

La fusion direct de ces deux tables renvoit un message d’erreur

# left_join(flights, airports)

En effet, il est nécessaire de préciser la variable qui fera le lien entre les deux tables via l’option by=. Pour simplifier l’affichage, nous effectuons les opérations sur des tables contenant moins de variables avec

flights_ex <- flights %>% select(origin, dest,  day, month)
airports_ex <- airports %>% select(faa, name, tzone)
left_join(flights_ex, airports_ex, by = c(origin = 'faa'))

Il existe plusieurs type de jointure suivant la relation entre les tables. Considérons les deux tables suivantes

prof_exp <- data.frame(nom = c('Bienvenue', 'Goffard', 'Milhaud', 'Clot', 'Bienvenue'), expertise = c('proba', 'None', 'stat', 'CS', 'CS'))
prof_exp

et

prof_prenom <- data.frame(nom = c('Bienvenue', 'Salhi'), prenom = c('Alexis', 'Yahia'))
prof_prenom

L’ordre dans lequel les tables sont passés en argument de la fonction left_join() a son importance.

left_join(prof_exp, prof_prenom, by = 'nom')
## Warning: Column `nom` joining factors with different levels, coercing to
## character vector

Chaque ligne présente dans prof_exp se retrouve dans le résultat de la fusion. La ligne Yahia présente dans prof_prenom mais pas dans prof_exp ne se retrouve pas dans la fusion. Les ligne Milhaud, Goffard et Clot sont dans la table issue de la fusion mais l’information pour la variable prenom est manquante car non-renseignée dans la table prof_prenom. Si on change l’ordre d’apparition dans left_join, c’est l’inverse

left_join(prof_prenom, prof_exp, by = 'nom')
## Warning: Column `nom` joining factors with different levels, coercing to
## character vector

Afin d’éviter les valeur manquante, on peut utiliser inner_join pour ne conserver que les lignes présentes dans chacune des deux tables.

inner_join(prof_exp, prof_prenom)
## Joining, by = "nom"
## Warning: Column `nom` joining factors with different levels, coercing to
## character vector

Références