II. Le Tidyverse I

Auteur·rice

Guillaume Guex

1 Le Tidyverse : qu’est-ce ?

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 fois
library(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
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
iris_tbl = as_tibble(iris)
iris_tbl
# A tibble: 150 × 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
 1          5.1         3.5          1.4         0.2 setosa 
 2          4.9         3            1.4         0.2 setosa 
 3          4.7         3.2          1.3         0.2 setosa 
 4          4.6         3.1          1.5         0.2 setosa 
 5          5           3.6          1.4         0.2 setosa 
 6          5.4         3.9          1.7         0.4 setosa 
 7          4.6         3.4          1.4         0.3 setosa 
 8          5           3.4          1.5         0.2 setosa 
 9          4.4         2.9          1.4         0.2 setosa 
10          4.9         3.1          1.5         0.1 setosa 
# ℹ 140 more rows

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 / cyl
mpg3 = mutate(mpg2, ratio=displ/cyl)
# On ne garde que les variables displ, cyl et ratio
mpg4 = select(mpg3, displ, cyl, ratio)
# On affiche les 3 premières lignes
head(mpg4, 3)
# A tibble: 3 × 3
  displ   cyl ratio
  <dbl> <int> <dbl>
1   1.8     4 0.45 
2   1.8     4 0.45 
3   2.8     6 0.467

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 :

head(
  select(
    mutate(
      filter(mpg, 
             year=="1999", class=="compact")
      , ratio=displ/cyl)
    , displ, cyl, ratio)
  , 3)
# A tibble: 3 × 3
  displ   cyl ratio
  <dbl> <int> <dbl>
1   1.8     4 0.45 
2   1.8     4 0.45 
3   2.8     6 0.467

Pour faciliter la lecture du code dans ce genre de situation, on peut utiliser le pipe:

mpg %>% 
  filter(year=="1999", class=="compact") %>%
  mutate(ratio=displ/cyl) %>%
  select(displ, cyl, ratio) %>%
  head(3)
# A tibble: 3 × 3
  displ   cyl ratio
  <dbl> <int> <dbl>
1   1.8     4 0.45 
2   1.8     4 0.45 
3   2.8     6 0.467

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 :

mpg2 = mpg %>% 
  filter(year=="1999", class=="compact") %>%
  mutate(ratio=displ/cyl) %>%
  select(displ, cyl, ratio)
head(mpg2)
# A tibble: 6 × 3
  displ   cyl ratio
  <dbl> <int> <dbl>
1   1.8     4 0.45 
2   1.8     4 0.45 
3   2.8     6 0.467
4   2.8     6 0.467
5   1.8     4 0.45 
6   1.8     4 0.45 

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 :

3.1 Chargement du jeu de données

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 :

final_df = raw_df %>%
  remove_empty(c("rows", "cols"))

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 crée un vecteur contenant les codes des variables :

codes = c("id", "h_deb", "h_fin", "mail", "milieu", 
          "acc_mode", "acc_exclu", "acc_accept", "acc_enrich", "acc_suppr", "acc_menace",
          "ou", "evite", "mots", "mots_plus", 
          "genre", "annee", "activite", "parle_ang", "lang_fr", "outils")

Notre table de recodage doit être utilisée sous le format d’un vecteur nommé, que l’on crée de la sorte :

lookup_vec = setNames(full_names, codes)
head(lookup_vec)
                                                                         id 
                                                                       "ID" 
                                                                      h_deb 
                                                           "Heure de début" 
                                                                      h_fin 
                                                             "Heure de fin" 
                                                                       mail 
                                                    "Adresse de messagerie" 
                                                                     milieu 
"D’après vous, dans quel(s) milieu(x) utilise-t-on le plus d’anglicismes ?" 
                                                                   acc_mode 
                     "« Nous utilisons des anglicismes par effet de mode »" 

Pour renommer nos noms de colonnes grâce à ce vecteur, on fait :

final_df = final_df %>%
  rename(all_of(lookup_vec))

Nos colonnes sont maintenant correctement nommées :

final_df
# A tibble: 113 × 21
      id h_deb               h_fin               mail  milieu acc_mode acc_exclu
   <dbl> <dttm>              <dttm>              <chr> <chr>  <chr>    <chr>    
 1    23 2020-12-18 19:42:31 2020-12-18 19:45:28 anon… Avec … Plutôt … Plutôt d…
 2    24 2020-12-18 19:51:15 2020-12-18 19:52:28 anon… Milie… Tout à … Tout à f…
 3    25 2020-12-18 19:55:03 2020-12-18 19:59:28 anon… Milie… Plutôt … Plutôt d…
 4    26 2020-12-18 21:02:00 2020-12-18 21:10:12 anon… Milie… Plutôt … Neutre   
 5    27 2020-12-18 21:19:17 2020-12-18 21:26:48 anon… Milie… Plutôt … Tout à f…
 6    28 2020-12-19 17:31:04 2020-12-19 17:38:11 anon… Avec … Plutôt … Plutôt d…
 7    29 2020-12-19 17:38:18 2020-12-19 17:43:12 anon… Avec … Plutôt … Neutre   
 8    30 2020-12-20 10:49:22 2020-12-20 10:54:39 anon… Milie… Plutôt … Neutre   
 9    31 2020-12-20 12:22:03 2020-12-20 12:31:58 anon… Milie… Tout à … Plutôt d…
10    32 2020-12-20 12:36:40 2020-12-20 12:41:19 anon… Milie… Neutre   Plutôt d…
# ℹ 103 more rows
# ℹ 14 more variables: acc_accept <chr>, acc_enrich <chr>, acc_suppr <chr>,
#   acc_menace <chr>, ou <chr>, evite <chr>, mots <chr>, mots_plus <chr>,
#   genre <chr>, annee <chr>, activite <chr>, parle_ang <chr>, lang_fr <chr>,
#   outils <chr>

3.4 Sélection des variables

Certaines variables de notre jeu de données ne sont pas pertinentes. Il est possible d’effectuer une sélection de variables avec select() :

final_df %>%
  select(acc_mode, acc_exclu, acc_accept, acc_enrich, acc_suppr, acc_menace)
# 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 “-” :

final_df = final_df %>%
  select(-mail, -mots_plus, -outils)

3.5 Filtrer des individus

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 :

final_df$h_deb < "2021-01-01"
  [1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [25]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [37]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [49]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [61]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [73]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [85]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [97]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[109]  TRUE  TRUE  TRUE FALSE FALSE

On peut donc sélectionner les individus pertinents avec filter() et une condition logique :

final_df = final_df %>%
  filter(h_deb < "2021-01-01")

L’aide de cette fonction fournit ne nombreuses manières d’écrire une condition logique permettant un filtre particulier.

3.6 Création de nouvelles variables

Pour créer de nouvelle variables, on utilise la fonction mutate().

Par exemple, si l’on veut créer une variable contenant la durée de l’entretien :

final_df = final_df %>%
  mutate(duree = h_fin - h_deb)

Ou en numérique :

final_df = final_df %>%
  mutate(duree_num = as.numeric(duree))
final_df
# 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 :

final_df = final_df %>%
  mutate(annee=str_extract(annee, regex("\\d{4}")))

Il s’agit maintenant de modifier le format de cette variable en nombre :

final_df = final_df %>%
  mutate(annee=as.numeric(annee))

3.7 Reconfiguration de la table

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) :

tibble(Noms=c("Individu 1", "Individu 2", "Individu 3"), 
       Hashtag=c(0, 1, 0), Selfie=c(0, 1, 1), Jetlag=c(1, 0, 0))
# A tibble: 3 × 4
  Noms       Hashtag Selfie Jetlag
  <chr>        <dbl>  <dbl>  <dbl>
1 Individu 1       0      0      1
2 Individu 2       1      1      0
3 Individu 3       0      1      0

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)
# A tibble: 111 × 5
   mot_1        mot_2     mot_3       mot_4       mot_5      
   <chr>        <chr>     <chr>       <chr>       <chr>      
 1 "Hashtag"    Design    "Selfie "   "Pull-over" "Parking"  
 2 "Design"     Pull-over "Parking"   "Football"  "Short"    
 3 "Shopping "  Casting   "Buzz"      "Parking"   "Pop-up"   
 4 "Fitness "   Start-up  "Sponsor"   "Shopping " "Week-end "
 5 "Feedback"   Eye liner "Football"  "Chill "    "Selfie "  
 6 "Tea-room"   Jetlag    "Pull-over" "Football"  "Cockpit " 
 7 "Dress code" Design    "Burn-out " "Pop-up"    "Selfie "  
 8 "Smartphone" Check-up  "Fitness "  "Start-up"  "Football" 
 9 "Cool "      Rider     "Pull-over" "Meeting"   "Short"    
10 "Fitness "   Jetlag    "Parking"   "Selfie "   "Feedback" 
# ℹ 101 more rows

L’opération inverse de separate() est unite(), qui permet d’agréger plusieurs colonnes en une seule.

On va mettre tous ces mots sur une seule colonne, en dupliquant le nombre de lignes. Cette opération se fait avec pivot_longer() :

table4a
# A tibble: 3 × 3
  country     `1999` `2000`
  <chr>        <dbl>  <dbl>
1 Afghanistan    745   2666
2 Brazil       37737  80488
3 China       212258 213766
table4a %>% 
  pivot_longer(cols=c("1999", "2000"), 
               names_to="year", 
               values_to="cases")
# A tibble: 6 × 3
  country     year   cases
  <chr>       <chr>  <dbl>
1 Afghanistan 1999     745
2 Afghanistan 2000    2666
3 Brazil      1999   37737
4 Brazil      2000   80488
5 China       1999  212258
6 China       2000  213766

Sur notre table cela donne :

aux_df = aux_df %>%
  pivot_longer(cols=mot_1:mot_39, 
               names_to="place", 
               values_to="word", 
               values_drop_na=T)
aux_df %>%
  select(id, place, word)
# A tibble: 2,642 × 3
      id place  word       
   <dbl> <chr>  <chr>      
 1    23 mot_1  "Hashtag"  
 2    23 mot_2  "Design"   
 3    23 mot_3  "Selfie "  
 4    23 mot_4  "Pull-over"
 5    23 mot_5  "Parking"  
 6    23 mot_6  "News"     
 7    23 mot_7  "Coach"    
 8    23 mot_8  "Meeting"  
 9    23 mot_9  "Football" 
10    23 mot_10 "Cool "    
# ℹ 2,632 more rows

On enlève les mots vides et la colonne place qui ne sont pas utiles :

aux_df = aux_df %>%
  filter(word != "") %>%
  select(-place)

On va également enlever tous les espaces supplémentaires de nos colonnes de type caractères :

aux_df = aux_df %>%
  mutate(across(where(is.character), str_trim))

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
table2 %>% 
  pivot_wider(names_from=type, values_from=count)
# A tibble: 6 × 4
  country      year  cases population
  <chr>       <dbl>  <dbl>      <dbl>
1 Afghanistan  1999    745   19987071
2 Afghanistan  2000   2666   20595360
3 Brazil       1999  37737  172006362
4 Brazil       2000  80488  174504898
5 China        1999 212258 1272915272
6 China        2000 213766 1280428583

On l’utilise alors (en créant au préalable une variable constante const) pour arriver à notre table finale :

final_df = aux_df %>%
  mutate(const = 1) %>%
  pivot_wider(names_from="word", values_from=const, values_fill=0)
final_df %>% 
  select(id, Hashtag:Coach)
# A tibble: 111 × 8
      id Hashtag Design Selfie `Pull-over` Parking  News Coach
   <dbl>   <dbl>  <dbl>  <dbl>       <dbl>   <dbl> <dbl> <dbl>
 1    23       1      1      1           1       1     1     1
 2    24       0      1      0           1       1     0     0
 3    25       0      1      1           1       1     0     1
 4    26       0      1      1           1       1     1     0
 5    27       1      1      1           1       1     1     1
 6    28       0      1      1           1       1     1     1
 7    29       1      1      1           1       1     1     1
 8    30       1      1      1           1       1     1     1
 9    31       1      1      1           1       1     1     1
10    32       0      1      1           1       1     1     1
# ℹ 101 more rows

3.8 Sauvegarde de la table finale

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 :

write_csv(final_df, "data/sociolinguistique_v1.csv")

On peut aussi sauvegarder notre table de codage, pour se rappeler de notre encodage :

lookup_df = tibble(full_names, codes)
write_csv(lookup_df, "data/lookup_table.csv")