Pour rappel, R est un langage statistique avec un ensemble de fonctions de base. Ces fonctionnalités peuvent être étendues grâce à l’utilisation de librairies. Il en existe un (très) grand nombre et il est parfois compliqué de choisir lesquelles utiliser. Un critère à prendre en compte est la personne et/ou l’entité qui la produit. Un développeur seul aura moins de temps pour développer/améliorer/maintenir une librairie qu’il a développé, par rapport à un laboratoire ou une entreprise.
L’équipe de R Studio a développé un ensemble de packages pour la Data Science dénommé tidyverse, et à la vue de l’expérience de l’entreprise, nous pouvons raisonnablement pensé que ceux-ci seront pérennes dans le temps. C’est pourquoi nous avons décidé de les présenter dans ce cours.
Dans la suite, nous allons donc voir quelques uns de ces librairies et leur utilisation. Il faut exécuter les commandes ci-dessous pour voir ce qu’elles réalisent, et ne pas hésiter à les modifier pour les comprendre.
Le package tibble permet de définir une nouvelle structure (tbl_df), basée sur un data.frame.
library(tibble)
as_tibble(mtcars)
Les différences avec un data.framesont minimes, mais importantes :
rownamesfactorLe tidyverse inclut trois packages permettant l’importation de données externes, contenues dans des fichiers (ainsi que l’exportation). Nous allons ici importer des données classiques (150 iris de trois espèces différentes, décrits par 4 variable), disponibles dans trois formats : texte délimité, Excel et SAS.
Les fonctions qu’on va utiliser renvoient un objet de type tibble. Pour plus d’options, il faut aller voir l’aide de chaque package.
Pour cela, nous utilisons le package readr, qui améliore les fonctions déjà présentes. Les nouvelles fonctions sont plutôt performantes, et comprennent les données, ce qui permet de limiter les besoins de paramétrisation de celles-ci.
library(readr)
iris_txt = read_delim("Iris.txt", delim = "\t")
Le package readxl permet donc de lire des fichiers Excel (quelque soit le format : xlsx ou xls). La fonction read_excel() détecte justement le format du fichier.
library(readxl)
iris_xlsx = read_excel("Iris.xlsx")
Enfin, pour importer des données SAS mais aussi SPSS et Stata, il existe le package haven, avec la fonction read_sas().
library(haven)
iris_sas = read_sas("Iris.sas7bdat")
JSONLe format JSON est un format très utilisées pour les données sur le web, qui sont souvent structurées autrement qu’avec des objets décrits par le même ensemble de variable.
Par exemple, le site SWAPI nous permet de récupére toutes les informations sur les personnages, planètes et vaisseaux spatiaux de la saga Star Wars. Le résultat en première page nous permet d’avoir un aperçu des objets JSON.
La librarie jsonlite permet de lire et d’écrire des données dans le format JSON.
library(jsonlite)
fromJSON("https://swapi.co/api/people/1/")
Pour lire une page web, nous pouvons utiliser le package rvest, qui permet donc de récupérer le contenu d’une page web.
library(rvest)
sw = read_html("https://www.imdb.com/title/tt0076759/")
Dans celle-ci, on sait que la note est dans la première balise span dans la div de la classe ratingValue. On peut la récupérer directement comme ci-dessous (la syntaxe avec %>% est expliquée plus tard).
sw %>% 
  html_nodes(".ratingValue span") %>% 
  head(1) %>% 
  html_text() %>%
  as.numeric()
Vous remarquerez l’utilisation de l’opérateur %>% pour enchaîner les opérations. Celui-ci est fournit par le package magrittr, lui aussi dans le tidyverse. Ce formalisme permet d’avoir un code plus lisible, car déroulant les étapes les unes après les autres, contrairement à la programmation classique dans R. Voici un exemple d’utilisation simple.
x = rnorm(1000)
mean(x)
x %>% mean()
Pour tout ce qui est manipulation de données, au sens SQL, nous disposons du package dplyr qui fournit toutes les fonctions utilisées ici. Bien qu’il y ait aussi des fonctions de base dans R, ce package est préférable.
library(dplyr)
Ici, les deux opérations consistent respectivement à sélectionner des lignes (restriction) ou des colonnes (projection).
mtcars %>% filter(mpg > 30)
mtcars %>% filter(mpg > 30 & qsec < 19)
mtcars %>% filter(carb == 8)
mtcars %>% filter(between(mpg, 30, 32))
mtcars %>% slice(1:5)
mtcars %>% slice(25:n()) # n() indique le nombre de lignes de la table
mtcars %>% slice(seq(1, n(), by = 4))
head(mtcars) %>% select(mpg)
head(mtcars) %>% select(qsec, mpg, hp)
head(mtcars) %>% select(5, 3, 9)
head(mtcars) %>% select(starts_with("c")) # d'autres possibilités de ce type existent (voir ?select_helpers)
head(mtcars) %>% select(cyl)
head(mtcars) %>% select(cyl) %>% distinct()
La fonction arrange() permet le tri sur une ou plusieurs variables, avec desc() pour indiquer un ordre décroissant.
head(mtcars) %>% arrange(mpg)
head(mtcars) %>% arrange(am, mpg)
head(mtcars) %>% arrange(desc(mpg))
Comme vous avez pu le remarquer, dans les différents exemples ci-dessus, le nom des lignes est supprimé. Pour le récupérer, nous utilisons la fonction rownames_to_column(), qui permet de le transformer en variable.
head(mtcars) %>% rownames_to_column(var = "car")
Pour ajouter une variable, il existe la fonction mutate().
head(mtcars) %>% mutate(ratio = wt / hp, zero = 0, wt = NULL, hp = NULL)
head(mtcars) %>% mutate(n = row_number(), rang_mpg = min_rank(desc(mpg)))
Si l’on veut garder uniquement la variable nouvellement créée, on utilise transmute().
head(mtcars) %>% transmute(ratio = wt / hp)
Pour résumer une ou plusieurs variables, nous utilisons la fonction summarise().
mtcars %>% summarise(
  n = n(),
  mpg_mean = mean(mpg),
  nbtype_carb = n_distinct(carb)
)
Et si l’on souhaite effecture par groupes déterminés par les modalités d’une variable, il existe la fonction group_by().
mtcars %>%
  group_by(cyl) %>%
  summarise(
  n = n(),
  mpg_mean = mean(mpg),
  nbtype_carb = n_distinct(carb)
)
Pour tester les méthodes, nous créons une nouvelle table engine, indiquant le type en fonction de la valeur de cyl. Vous remarquerez que par rapport à mtcars, il y a une valeur en moins (4) et une valeur en plus (12).
engine = tibble(
  cyl = c(6, 8, 12),
  type = c("medium", "big", "very big")
)
Nous pouvons maintenant utiliser les différentes fonctions de jointure disponibles.
mtcars %>% inner_join(engine)
mtcars %>% left_join(engine)
mtcars %>% right_join(engine)
mtcars %>% full_join(engine)
mtcars %>% semi_join(engine)
mtcars %>% anti_join(engine)
Il est parfois utile de modifer la structure des données, par exemple dans le cadre d’une visualisation de données avec ggplot que nous verrons plus tard. Dans ce cas, plutôt que d’avoir un tableau individus décrits par des variables, il est nécessaire d’avoir un tableau à trois variables : individu, variable, valeur de la variable. Le package tidyr contient les fonctions nécessaires pour faire les opérations dans les deux sens (et donc de pouvoir faire une transposée en réalisant une double opération).
Pour créer une table longue à partir d’une table large, nous utilisons gather().
tab_longue = mtcars %>% 
  rownames_to_column("car") %>%
  as_tibble() %>%
  gather(variable, value, -car)
tab_longue
A l’inverse, pour avoir une table large à partir d’une table longue, c’est la fonction spread(). On réalise ici la transposée de la table mtcars.
tab_large 
tab_longue %>%
  spread(car, value)
Le package stringr permet de gérer les chaînes de caractères de manière plus simple que les fonctions de base. Voici quelques exemples de manipulations classiques.
library(stringr)
mt = mtcars %>% rownames_to_column("car")
str_length(mt$car)
str_c(mt$car, collapse = ", ")
str_sub(mt$car, 1, 3)
Une expression régulière permet de décrire une chaîne de caractères, pour retrouver toutes les chaînes correspondant à la description. C’est un outil très puissant, et pas forcément simple à maîtriser.
str_subset(mt$car, "Merc")
str_subset(mt$car, "[0-9]")
str_detect(mt$car, "[0-9]")
str_match(mt$car, "(.+)[ ](.+)")
str_split(mt$car, " ")
Ici, c’est le package lubridate qu’il faut utiliser pour manipuler facilement les dates, comme dans les exemples ci-dessous.
library(lubridate)
now()
today = today()
today
year(today)
month(today)
month(today, label = TRUE)
month(today, label = TRUE, abbr = FALSE)
day(today)
mday(today)
wday(today)
wday(today, label = TRUE)
wday(today, label = TRUE, week_start = 1)
wday(today, week_start = 1)
yday(today)
Ce package permet de définir des périodes, et donc de les ajouter à une date (par exemple, pour avoir la date un an après un évènement).
today + period(week = 1, day = 3)
today + period("1W 3D")
today - years(1) - days(10)
On peut avoir faire des différences entre dates (par défaut en jour), et avoir cette valeur en secondes ou en années.
bday = ymd("19771114")
diff = today - bday
diff
as.period(diff)
as.duration(diff)
Enfin, on peut même évaluer si une date est dans un intervale ou non.
nextyear = today + years(1)
int = interval(today, nextyear)
ymd("20190101") %within% int
ymd("20191101") %within% int
Pour information, la librairie hms permet elle de gérer les heures, minutes et secondes mais nous ne les verrons pas ici.
La banque mondiale fournit un grand nombre de données, dont des indicateurs de gouvernance au niveau mondial (voir ici), pour la période 1996-2016.
Vous trouverez les informations dans ces quatre fichiers :
tibblestibbleTypeCode est "EST"."CC" et le type "EST", quelles sont les valeurs moyenne, maximale et minimale ? (utiliser la table longue)"Estimate".