Le Tidyverse (https://www.tidyverse.org/) est une collection de plusieurs librairies, créé par posit (RStudio), spécialement conçue pour le traitement de données dans R. On y trouve par exemple :
dplyr / tidyr / tibble : packages pour la manipulation de jeux de données
stringr : package pour la manipulation de chaînes de caractères
ggplot2 : package pour la création de graphiques
Ces librairies partagent une “philosophie” de programmation commune qui change la manière habituelle de programmer en R, en particulier grâce à (ou à cause de) l’opérateur pipe: %>%. Cette philosophie permet d’avoir des codes très lisibles, mais peut parfois être déroutante pour les personnes habituées à la base de R.
L’utilisation du tidyverse devient de plus en plus importante dans la communauté R, il est donc important de le voir si l’on veut continuer à comprendre les codes R trouvés en ligne.
Le tidyverse s’installe et se charge de la manière habituelle
# install.packages("tidyverse") # à décommenter pour installer la première foislibrary(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Dans ce code, nous allons également besoin de lire des fichiers excel, nous chargeons donc également readxl (pour rappel: on met généralement au début du code tous les packages que nous allons utiliser).
library(readxl)
Dans ce TP nous allons également utiliser la fonction remove_empty() du package janitor, qui permet d’enlever les lignes et colonnes vides d’un jeu de données.
library(janitor)
Attachement du package : 'janitor'
Les objets suivants sont masqués depuis 'package:stats':
chisq.test, fisher.test
Ce TP s’inspire fortement du livre R for Data Science (2017), de Garrett Grolemund et Hadley Wickham, disponible en ligne : https://r4ds.had.co.nz/.
2 Éléments centraux du Tidyverse
2.1 Les tibbles
Les données dans le tidyverse se présentent sous la forme de tibbles, c’est-à-dire une sorte de dataframe mais avec quelques avantages par rapport à ces dernières. La plupart des opérations sur les dataframes sont possibles, mais les tibbles présentent l’avantage d’avoir un affichage plus élégant et des types de données plus variés. On trouve comme tibble d’exemple contenu dans le tidyverse :
mpg
# A tibble: 234 × 11
manufacturer model displ year cyl trans drv cty hwy fl class
<chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
1 audi a4 1.8 1999 4 auto… f 18 29 p comp…
2 audi a4 1.8 1999 4 manu… f 21 29 p comp…
3 audi a4 2 2008 4 manu… f 20 31 p comp…
4 audi a4 2 2008 4 auto… f 21 30 p comp…
5 audi a4 2.8 1999 6 auto… f 16 26 p comp…
6 audi a4 2.8 1999 6 manu… f 18 26 p comp…
7 audi a4 3.1 2008 6 auto… f 18 27 p comp…
8 audi a4 quattro 1.8 1999 4 manu… 4 18 26 p comp…
9 audi a4 quattro 1.8 1999 4 auto… 4 16 25 p comp…
10 audi a4 quattro 2 2008 4 manu… 4 20 28 p comp…
# ℹ 224 more rows
Il est possible de passer d’une dataframe à un tibble avec as_tibble() :
head(iris) # head() donne seulement les premières observations
L’opération inverse n’est généralement pas nécessaire, car un tibble est un dataframe, toutes les opérations que l’on effectue sur un dataframe sont valables sur un tibble.
2.2 Le pipe (%>%)
Avec le tidyverse, on utilise fréquemment l’opérateur pipe, noté %>%. Pour comprendre son utilisation, prenons un exemple simple de manipulations (nous verrons ces fonctions par la suite) :
# On ne garde que les modèles de classe "compact" de l'année "1999"mpg2 =filter(mpg, year=="1999", class=="compact")# On calcule une nouvelle variable ratio = displ / cylmpg3 =mutate(mpg2, ratio=displ/cyl)# On ne garde que les variables displ, cyl et ratiompg4 =select(mpg3, displ, cyl, ratio)# On affiche les 3 premières ligneshead(mpg4, 3)
Cette suite d’opérations n’est pas idéale, car nous avons créé un nouveau tibble pour chaque opération. On aurait aussi pu emboîter les opérations les unes dans les autres, mais la lisibilité devient difficile :
Grâce au pipe, l’objet sortant (résultat de l’opération à gauche du pipe) vient se mettre à la place premier argument de la fonction qui suit (il n’y donc plus besoin de donner le premier argument). Cette façon de coder permet de se concentrer sur les “verbes” (les noms des fonctions) et les “compléments” (les arguments) plutôt que les “noms” (les variables).
Bien entendu, on peut toujours stocker le résultat d’une série d’opérations avec pipe dans une nouvelle variable :
Notez que depuis la version R 4.1.0, on peut également utiliser l’opérateur |> à la place de %>%.
3 Pré-traitements des données
Après avoir chargé un jeux de données, l’étape suivante consiste généralement à effectuer des pré-traitements sur ce dernier, afin de pouvoir faire nos analyses par la suite. Le tidyverse offre de nombreuses fonctions qui permettent de faire ces pré-traitements :
remove_empty() (package janitor) : enlève les lignes ou colonnes vides.
rename() : renomme les colonnes.
select() : sélectionne des variables.
mutate() : crée de nouvelles variables.
filter() : sélectionne des individus.
separate(), unite()pivot_longer(), pivot_wider() : opérations de reconfiguration d’une table.
(Non vu ici) inner_join(), left_join(), right_join(), full_join() : opérations de jointure entre deux tables.
Nous allons utiliser ces différentes opérations sur le jeu de données sociolinguistique_raw.xlsx, qui contient des données sur la perception des anglicismes par de nombreux individus (pour plus de détails, voir data/Margot_2022.pdf).
La plupart des opérations vues ici sont disponibles sous la forme de cheatsheets (feuilles de triche) publiées par Posit https://posit.co/resources/cheatsheets/). Ici, on utilise principalement :
Notre de jeu de données est contenu dans le dossier data/, qui se situe juste à côté de notre script, nous allons donc commencer par le charger dans R :
# `read_excel()` est une fonction du package `readxl`raw_df =read_excel("data/sociolinguistique_raw.xlsx")
On peut ensuite voir notre jeu de données en cliquant sur l’icone à côté de son nom dans l’environnement, ou avec :
view(raw_df)
En l’état, ce jeu est difficile à analyser. Nous allons préparer ces données pour de futures analyses.
3.2 Suppression des lignes et colonnes vides
On commence par supprimer toutes les colonnes et lignes vides, pour cela, on utilise remove_empty() du package janitor :
On peut voir qu’il y a toujours 113 lignes, mais qu’il ne nous reste plus que 21 colonnes pertinentes :
final_df
# A tibble: 113 × 21
ID `Heure de début` `Heure de fin` `Adresse de messagerie`
<dbl> <dttm> <dttm> <chr>
1 23 2020-12-18 19:42:31 2020-12-18 19:45:28 anonymous
2 24 2020-12-18 19:51:15 2020-12-18 19:52:28 anonymous
3 25 2020-12-18 19:55:03 2020-12-18 19:59:28 anonymous
4 26 2020-12-18 21:02:00 2020-12-18 21:10:12 anonymous
5 27 2020-12-18 21:19:17 2020-12-18 21:26:48 anonymous
6 28 2020-12-19 17:31:04 2020-12-19 17:38:11 anonymous
7 29 2020-12-19 17:38:18 2020-12-19 17:43:12 anonymous
8 30 2020-12-20 10:49:22 2020-12-20 10:54:39 anonymous
9 31 2020-12-20 12:22:03 2020-12-20 12:31:58 anonymous
10 32 2020-12-20 12:36:40 2020-12-20 12:41:19 anonymous
# ℹ 103 more rows
# ℹ 17 more variables:
# `D’après vous, dans quel(s) milieu(x) utilise-t-on le plus d’anglicismes ?` <chr>,
# `« Nous utilisons des anglicismes par effet de mode »` <chr>,
# `« Les anglicismes excluent certains locuteurs plus âgés »` <chr>,
# `« On est obligé d’utiliser des anglicismes pour se faire accepter en société »` <chr>,
# `« Les anglicismes enrichissent la langue française »` <chr>, …
3.3 Renommer les colonnes
Les noms des colonnes s’obtiennent avec :
names(final_df)
[1] "ID"
[2] "Heure de début"
[3] "Heure de fin"
[4] "Adresse de messagerie"
[5] "D’après vous, dans quel(s) milieu(x) utilise-t-on le plus d’anglicismes ?"
[6] "« Nous utilisons des anglicismes par effet de mode »"
[7] "« Les anglicismes excluent certains locuteurs plus âgés »"
[8] "« On est obligé d’utiliser des anglicismes pour se faire accepter en société »"
[9] "« Les anglicismes enrichissent la langue française »"
[10] "« Il faudrait supprimer l’anglais dans les publicités, affiches, magazines et médias »"
[11] "« Les anglicismes constituent une menace pour la langue française »"
[12] "Où avez-vous l’impression d'entendre le plus d’anglicismes ?"
[13] "Dans la mesure du possible essayez-vous d’éviter les anglicismes ?"
[14] "Parmi les mots suivants, cochez ceux que vous utilisez:"
[15] "Pouvez-vous compléter cette liste avec 5 autres anglicismes (Si rien ne vous vient, vous pouvez passer à la suite)?"
[16] "Vous êtes"
[17] "Quelle est votre année de naissance ?"
[18] "Vous êtes principalement"
[19] "Parlez-vous anglais ?"
[20] "Le français est-il votre langue principale à la maison?"
[21] "Parmi les outils technologiques suivant, lesquels utilisez-vous plusieurs fois par semaine?"
Dans le tidyverse, la plupart des opérations se font à l’aide des noms de colonnes, c’est pourquoi il est utile d’avoir des noms qui sont courts et si possible respectant les règles de nommage des variables R (pas d’espace, pas de caractères spéciaux, etc.)
Pour renommer une ou plusieurs colonne, on peut faire :
final_df %>%rename(h_deb ="Heure de début",h_fin ="Heure de fin")
# A tibble: 113 × 21
ID h_deb h_fin `Adresse de messagerie`
<dbl> <dttm> <dttm> <chr>
1 23 2020-12-18 19:42:31 2020-12-18 19:45:28 anonymous
2 24 2020-12-18 19:51:15 2020-12-18 19:52:28 anonymous
3 25 2020-12-18 19:55:03 2020-12-18 19:59:28 anonymous
4 26 2020-12-18 21:02:00 2020-12-18 21:10:12 anonymous
5 27 2020-12-18 21:19:17 2020-12-18 21:26:48 anonymous
6 28 2020-12-19 17:31:04 2020-12-19 17:38:11 anonymous
7 29 2020-12-19 17:38:18 2020-12-19 17:43:12 anonymous
8 30 2020-12-20 10:49:22 2020-12-20 10:54:39 anonymous
9 31 2020-12-20 12:22:03 2020-12-20 12:31:58 anonymous
10 32 2020-12-20 12:36:40 2020-12-20 12:41:19 anonymous
# ℹ 103 more rows
# ℹ 17 more variables:
# `D’après vous, dans quel(s) milieu(x) utilise-t-on le plus d’anglicismes ?` <chr>,
# `« Nous utilisons des anglicismes par effet de mode »` <chr>,
# `« Les anglicismes excluent certains locuteurs plus âgés »` <chr>,
# `« On est obligé d’utiliser des anglicismes pour se faire accepter en société »` <chr>,
# `« Les anglicismes enrichissent la langue française »` <chr>, …
Mais comme notre table est longue , nous allons plutôt utiliser une table de recodage.
On commence par créer un vecteur contenant les noms des lignes actuels :
full_names =names(final_df)
Puis on sauvegarde ces noms dans un fichier de données que nous allons éditer à la main pour créer notre table de recodage :
Le fichier, une fois édité, s’appelle lookup_table.csv. Nous allons maintenant le charger dans R pour l’utiliser comme table de recodage :
lookup_df =read_csv("data/lookup_table.csv")
Rows: 21 Columns: 2
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): codes, full_names
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
lookup_df
# A tibble: 21 × 2
codes full_names
<chr> <chr>
1 id ID
2 h_deb Heure de début
3 h_fin Heure de fin
4 mail Adresse de messagerie
5 milieu D’après vous, dans quel(s) milieu(x) utilise-t-on le plus d’angli…
6 acc_mode « Nous utilisons des anglicismes par effet de mode »
7 acc_exclu « Les anglicismes excluent certains locuteurs plus âgés »
8 acc_accept « On est obligé d’utiliser des anglicismes pour se faire accepter…
9 acc_enrich « Les anglicismes enrichissent la langue française »
10 acc_suppr « Il faudrait supprimer l’anglais dans les publicités, affiches, …
# ℹ 11 more rows
Le recode se fait ensuite avec les commandes (deframe() transforme une table à deux colonnes en un vecteur de recodage) :
# A tibble: 113 × 6
acc_mode acc_exclu acc_accept acc_enrich acc_suppr acc_menace
<chr> <chr> <chr> <chr> <chr> <chr>
1 Plutôt d'accord Plutôt d'acc… Neutre Neutre Plutôt e… Plutôt en…
2 Tout à fait d'accord Tout à fait … Plutôt en… En désacc… Tout à f… Tout à fa…
3 Plutôt en désaccord Plutôt d'acc… Plutôt en… Plutôt d'… Plutôt e… Plutôt en…
4 Plutôt d'accord Neutre Plutôt en… Plutôt en… Neutre Plutôt d'…
5 Plutôt d'accord Tout à fait … Neutre Plutôt en… Neutre Plutôt d'…
6 Plutôt d'accord Plutôt d'acc… Plutôt en… Plutôt d'… Plutôt e… Plutôt d'…
7 Plutôt d'accord Neutre Plutôt en… Plutôt d'… En désac… En désacc…
8 Plutôt d'accord Neutre Neutre Plutôt d'… Plutôt e… Plutôt en…
9 Tout à fait d'accord Plutôt d'acc… Plutôt d'… Plutôt en… Neutre Plutôt d'…
10 Neutre Plutôt d'acc… Plutôt d'… Plutôt d'… Plutôt d… Plutôt d'…
# ℹ 103 more rows
Notez que select() s’utilise de nombreuses manières (voir l’aide). Ici, nous aimerions surtout éliminer certaines colonnes, on peut pour cela utiliser l’opérateur “-” :
La fonction filter() permet quant à elle de filtrer les individus selon des conditions logiques. Supposons que les données des individus dont l’entretien s’est déroulé après le 1 janvier 2021 ont été enregistrées de manière erronée, et que nous désirons enlever ces lignes.
Tester les dates selon cette condition correspond à l’expression suivante :
# A tibble: 111 × 20
id h_deb h_fin milieu acc_mode acc_exclu
<dbl> <dttm> <dttm> <chr> <chr> <chr>
1 23 2020-12-18 19:42:31 2020-12-18 19:45:28 Avec les am… Plutôt … Plutôt d…
2 24 2020-12-18 19:51:15 2020-12-18 19:52:28 Milieu prof… Tout à … Tout à f…
3 25 2020-12-18 19:55:03 2020-12-18 19:59:28 Milieu prof… Plutôt … Plutôt d…
4 26 2020-12-18 21:02:00 2020-12-18 21:10:12 Milieu prof… Plutôt … Neutre
5 27 2020-12-18 21:19:17 2020-12-18 21:26:48 Milieu prof… Plutôt … Tout à f…
6 28 2020-12-19 17:31:04 2020-12-19 17:38:11 Avec les am… Plutôt … Plutôt d…
7 29 2020-12-19 17:38:18 2020-12-19 17:43:12 Avec les am… Plutôt … Neutre
8 30 2020-12-20 10:49:22 2020-12-20 10:54:39 Milieu prof… Plutôt … Neutre
9 31 2020-12-20 12:22:03 2020-12-20 12:31:58 Milieu prof… Tout à … Plutôt d…
10 32 2020-12-20 12:36:40 2020-12-20 12:41:19 Milieu prof… Neutre Plutôt d…
# ℹ 101 more rows
# ℹ 14 more variables: acc_accept <chr>, acc_enrich <chr>, acc_suppr <chr>,
# acc_menace <chr>, ou <chr>, evite <chr>, mots <chr>, genre <chr>,
# annee <chr>, activite <chr>, parle_ang <chr>, lang_fr <chr>, duree <drtn>,
# duree_num <dbl>
La variable annee, contenant le date de naissance, contient des entrées incohérentes. Nous allons utiliser une expressions régulière (4 “digits”) et la fonction str_extract() pour extraire l’année de naissance sur chaque entrée :
Il existe également de nombreuses opérations (separate(), unite()pivot_longer(), pivot_wider(), etc.), plus complexes, qui permettent de “reconfigurer” notre table de données.
Pour comprendre ces opérations, nous allons essayer d’extraire les mots de la colonne mots, afin d’avoir ces derniers comme variables binaires représentant l’utilisation (ou non) de ce mot par l’individu. En résumé, un tableau de cette forme (0 = non-utilisation, 1 = utilisation) :
Pour commencer, on sépare la colonne “mots” en plusieurs colonnes, contenant sur chacune un mot de la liste (ou des valeurs maquantes), avec la fonction separate() :
# Ci-dessous, paste0("mot_", 1:39) crée un vecteur de chaînes de caractères# contenant ("mot_1", "mot_2", "mot_3", ... , "mot_39"), i.e., les noms des # nouvelles colonnes.aux_df = final_df %>%separate(mots, into=paste0("mot_", 1:39), sep=";", fill="right")aux_df %>%select(mot_1:mot_5)
L’opération inverse de pivot_longer() est pivot_wider(), qui fonctionne de la manière suivante :
table2
# A tibble: 12 × 4
country year type count
<chr> <dbl> <chr> <dbl>
1 Afghanistan 1999 cases 745
2 Afghanistan 1999 population 19987071
3 Afghanistan 2000 cases 2666
4 Afghanistan 2000 population 20595360
5 Brazil 1999 cases 37737
6 Brazil 1999 population 172006362
7 Brazil 2000 cases 80488
8 Brazil 2000 population 174504898
9 China 1999 cases 212258
10 China 1999 population 1272915272
11 China 2000 cases 213766
12 China 2000 population 1280428583
Une fois tous les pré-traitements effectués, on peut sauvegarder notre table finale. Cela nous permettera de travailler sur le traitement statistique dans un autre script :