III. Le Tidyverse II et les statistiques uni- et bi-variées

Auteur·rice

Guillaume Guex

1 Préparation du jeu de données

Pour ce TP nous allons avoir besoin des librairies suivantes :

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
library(readxl)
library(janitor)

Attachement du package : 'janitor'

Les objets suivants sont masqués depuis 'package:stats':

    chisq.test, fisher.test
library(DescTools)

1.1 Chargement et aperçu des données

Dans ce TP, nous allons utiliser le jeu de données data/pragmatique.xlsx, qui porte sur une sélection de marqueurs de doute, prononcés dans différents contextes. Une description de ce jeu de données se trouve dans le fichier data/pragmatique_info.docx.

Commençons par charger le jeu de données :

pragmatique_df = read_excel("data/pragmatique.xlsx")
pragmatique_df
# A tibble: 321 × 20
   `ID marqueur` Evénement Année Genre         `Timing début` `Timing fin` Lemme
           <dbl> <chr>     <dbl> <chr>                  <dbl>        <dbl> <chr>
 1         20001 DPU_UDC    2007 Débat public          804366       804552 SEMB…
 2         20002 DPU_REC    2007 Débat public         1352035      1352284 PARA…
 3         20003 DPU_UDC    2007 Débat public         1888187      1888333 PARA…
 4         20004 DTV_SM1    2007 Débat télévi…         340280       341094 PARA…
 5         20005 DTV_SM2    2013 Débat télévi…         880398       880572 PARA…
 6         20006 REU_BL1    2017 Réunion prof…        2729947      2730002 PARA…
 7         20007 DPU_MED    2008 Débat public         2878433      2878820 AVOI…
 8         20008 DTV_DEM    2007 Débat télévi…        3199465      3199624 AVOI…
 9         20009 DTV_VEH    2007 Débat télévi…         463064       463380 AVOI…
10         20010 DPU_BIE    2009 Débat public         2384187      2385363 AVOI…
# ℹ 311 more rows
# ℹ 13 more variables: `POS-TAG` <chr>, `Type morpho-syntaxique` <chr>,
#   `Position du marqueur dans l'UCT` <chr>,
#   `Position de l'UCT dans le TDP` <chr>,
#   `Rôle de l'UCT dans la séquence` <chr>, `Regard avant le marqueur` <chr>,
#   `Regard pendant le marqueur` <chr>, `Regard après le marqueur` <chr>,
#   `Présence d'un geste?` <chr>, `Type de geste` <chr>, Direction <chr>, …

Le jeu semble relativement propre, on peut voir un résumé rapide de ses variables avec :

pragmatique_df %>%
  str()
tibble [321 × 20] (S3: tbl_df/tbl/data.frame)
 $ ID marqueur                    : num [1:321] 20001 20002 20003 20004 20005 ...
 $ Evénement                      : chr [1:321] "DPU_UDC" "DPU_REC" "DPU_UDC" "DTV_SM1" ...
 $ Année                          : num [1:321] 2007 2007 2007 2007 2013 ...
 $ Genre                          : chr [1:321] "Débat public" "Débat public" "Débat public" "Débat télévisé" ...
 $ Timing début                   : num [1:321] 804366 1352035 1888187 340280 880398 ...
 $ Timing fin                     : num [1:321] 804552 1352284 1888333 341094 880572 ...
 $ Lemme                          : chr [1:321] "SEMBLER" "PARAÎTRE" "PARAÎTRE" "PARAÎTRE" ...
 $ POS-TAG                        : chr [1:321] "verbe" "verbe" "verbe" "verbe" ...
 $ Type morpho-syntaxique         : chr [1:321] "construction attributive à verbe copule" "construction attributive à verbe copule" "construction attributive à verbe copule" "construction attributive à verbe copule" ...
 $ Position du marqueur dans l'UCT: chr [1:321] "milieu" "début*" "milieu" "début*" ...
 $ Position de l'UCT dans le TDP  : chr [1:321] "milieu" "milieu" "milieu" "milieu" ...
 $ Rôle de l'UCT dans la séquence : chr [1:321] "indéterminé" "indéterminé" "indéterminé" "indéterminé" ...
 $ Regard avant le marqueur       : chr [1:321] "allocutaire(s)" "allocutaire(s)" "allocutaire(s)" "autre" ...
 $ Regard pendant le marqueur     : chr [1:321] "allocutaire(s)" "autre" "allocutaire(s)" "indéterminable" ...
 $ Regard après le marqueur       : chr [1:321] "allocutaire(s)" "autre" "allocutaire(s)" "autre" ...
 $ Présence d'un geste?           : chr [1:321] "non" "oui" "oui" "impossible à déterminer" ...
 $ Type de geste                  : chr [1:321] NA "Meta.Aura" "Deictic.Addressee" NA ...
 $ Direction                      : chr [1:321] "à l'intérieur" "à l'intérieur" "à l'intérieur" "portée<marqueur" ...
 $ Source                         : chr [1:321] "ML" "ML" "ML" "ML" ...
 $ Polarité                       : chr [1:321] "positive" "positive" "positive" "positive" ...

Cependant ATTENTION, le nom de la plupart des variables ne respecte pas une syntaxe propre à R (en l’occurrence, il y a des espaces dans les noms) :

names(pragmatique_df)
 [1] "ID marqueur"                     "Evénement"                      
 [3] "Année"                           "Genre"                          
 [5] "Timing début"                    "Timing fin"                     
 [7] "Lemme"                           "POS-TAG"                        
 [9] "Type morpho-syntaxique"          "Position du marqueur dans l'UCT"
[11] "Position de l'UCT dans le TDP"   "Rôle de l'UCT dans la séquence" 
[13] "Regard avant le marqueur"        "Regard pendant le marqueur"     
[15] "Regard après le marqueur"        "Présence d'un geste?"           
[17] "Type de geste"                   "Direction"                      
[19] "Source"                          "Polarité"                       

Ce qui veut dire que, pour les utiliser, on les entourera de `` (accents graves). Par exemple pour sortir le vecteur Timing début :

head(pragmatique_df$`Timing début`, 20)
 [1]  804366 1352035 1888187  340280  880398 2729947 2878433 3199465  463064
[10] 2384187 3480664 1996191 3146178 2888539 1431198 2522231 3934802   20296
[19] 5777249 2018074

1.2 Pré-traitements

La dernière fois, nous avons vu comment utiliser le package janitor pour nettoyer les lignes et colonnes vides. Nous pouvons aussi l’utiliser pour renommer automatiquement les noms de variables de manière “adéquate” pour R.

pragmatique_df = pragmatique_df %>%
  clean_names()
names(pragmatique_df)
 [1] "id_marqueur"                     "evenement"                      
 [3] "annee"                           "genre"                          
 [5] "timing_debut"                    "timing_fin"                     
 [7] "lemme"                           "pos_tag"                        
 [9] "type_morpho_syntaxique"          "position_du_marqueur_dans_l_uct"
[11] "position_de_l_uct_dans_le_tdp"   "role_de_l_uct_dans_la_sequence" 
[13] "regard_avant_le_marqueur"        "regard_pendant_le_marqueur"     
[15] "regard_apres_le_marqueur"        "presence_dun_geste"             
[17] "type_de_geste"                   "direction"                      
[19] "source"                          "polarite"                       

Nous allons créer une nouvelle variable, qui correspond à la durée du Lemme :

pragmatique_df = pragmatique_df %>% 
  mutate(duree=timing_fin - timing_debut)
pragmatique_df %>% select(duree)
# A tibble: 321 × 1
   duree
   <dbl>
 1   186
 2   249
 3   146
 4   814
 5   174
 6    55
 7   387
 8   159
 9   316
10  1176
# ℹ 311 more rows

Il est possible de recoder une variable numérique (p.ex. duree) en variable catégorielle avec case_when() :

pragmatique_df = pragmatique_df %>%
  mutate(duree_cat=case_when(
    duree <= 385 ~ "court",
    (duree > 385) & (duree <= 563) ~ "moyen",
    duree > 563 ~ "long"
  ))
pragmatique_df %>%
  select(duree, duree_cat) %>%
  head(10)
# A tibble: 10 × 2
   duree duree_cat
   <dbl> <chr>    
 1   186 court    
 2   249 court    
 3   146 court    
 4   814 long     
 5   174 court    
 6    55 court    
 7   387 moyen    
 8   159 court    
 9   316 court    
10  1176 long     

Finalement, pour les graphiques est certaines fonctions statistiques, il est utile de transformer les variables de type “character” en type “factor” (véritables variables catégorielles dans R). On peut le faire avec as.factor() :

pragmatique_df = pragmatique_df %>%
  mutate(lemme=as.factor(lemme))
head(pragmatique_df$lemme)
[1] SEMBLER  PARAÎTRE PARAÎTRE PARAÎTRE PARAÎTRE PARAÎTRE
9 Levels: APPAREMMENT AVOIR L'AIR AVOIR L'IMPRESSION ... VISIBLEMENT

On peut appliquer cette logique à l’ensemble des variables de type “character” du jeu de données avec l’aide de la fonction accross() (on s’assure au préalable que les modalités ne possède pas d’espaces en trop) :

pragmatique_df = pragmatique_df %>%
  mutate(across(where(is.character), str_squish)) %>%
  mutate(across(where(is.character), as.factor))
pragmatique_df
# A tibble: 321 × 22
   id_marqueur evenement annee genre       timing_debut timing_fin lemme pos_tag
         <dbl> <fct>     <dbl> <fct>              <dbl>      <dbl> <fct> <fct>  
 1       20001 DPU_UDC    2007 Débat publ…       804366     804552 SEMB… verbe  
 2       20002 DPU_REC    2007 Débat publ…      1352035    1352284 PARA… verbe  
 3       20003 DPU_UDC    2007 Débat publ…      1888187    1888333 PARA… verbe  
 4       20004 DTV_SM1    2007 Débat télé…       340280     341094 PARA… verbe  
 5       20005 DTV_SM2    2013 Débat télé…       880398     880572 PARA… verbe  
 6       20006 REU_BL1    2017 Réunion pr…      2729947    2730002 PARA… verbe  
 7       20007 DPU_MED    2008 Débat publ…      2878433    2878820 AVOI… locuti…
 8       20008 DTV_DEM    2007 Débat télé…      3199465    3199624 AVOI… locuti…
 9       20009 DTV_VEH    2007 Débat télé…       463064     463380 AVOI… locuti…
10       20010 DPU_BIE    2009 Débat publ…      2384187    2385363 AVOI… locuti…
# ℹ 311 more rows
# ℹ 14 more variables: type_morpho_syntaxique <fct>,
#   position_du_marqueur_dans_l_uct <fct>, position_de_l_uct_dans_le_tdp <fct>,
#   role_de_l_uct_dans_la_sequence <fct>, regard_avant_le_marqueur <fct>,
#   regard_pendant_le_marqueur <fct>, regard_apres_le_marqueur <fct>,
#   presence_dun_geste <fct>, type_de_geste <fct>, direction <fct>,
#   source <fct>, polarite <fct>, duree <dbl>, duree_cat <fct>

2 Statistiques uni- et bi-variées

Pour commencer, nous allons faire des statistiques uni-variées sur des vecteurs. Nous verrons comment utiliser ses fonctions dans le cadre du tidyverse dans Section 3.

2.1 Statistiques uni-variées sur une variable numérique

Les statistiques uni-variées classiques sur des variables numériques sont les suivantes :

  • La moyenne, indicateur de tendance centrale.
  • La médiane, indicateur de tendance centrale moins sensible aux valeurs extrêmes.
  • La variance et l’écart-type, indicateurs de dispersion.
  • Le minimum et maximum, autres indicateurs de dispersion.
  • Les quantiles, coupant la distribution en plusieurs groupes de proportions pré-définies.

Pour faire la moyenne, la fonction à utiliser est mean() :

mean(pragmatique_df$duree)
[1] 571.1184

La médiane s’obtient avec median() :

median(pragmatique_df$duree)
[1] 481

La variance avec var() :

var(pragmatique_df$duree)
[1] 142354.2

L’unité de la variance est l’unité de la variable au carré. Pour obtenir une valeur dans la même unité que notre variable, on calcule l’écart-type, qui correspond à la racine carrée de la variance :

sd(pragmatique_df$duree)
[1] 377.2985
sqrt(var(pragmatique_df$duree))
[1] 377.2985

Si notre variable se distribue selon une loi normale, on sait qu’à-peu-près 95% des valeurs sont comprises entre +/- deux fois l’écart-type (1.96 pour être plus précis) :

mean(pragmatique_df$duree) - 1.96*sd(pragmatique_df$duree)
[1] -168.3867
mean(pragmatique_df$duree) + 1.96*sd(pragmatique_df$duree)
[1] 1310.623

Les valeurs minimale et maximale s’obtiennent respectivement avec min() et max() :

min(pragmatique_df$duree)
[1] 0
max(pragmatique_df$duree)
[1] 2815

Il existe une infinité de quantiles différents. Ils sont définis par rapport à un pourcentage. Par exemple, on parle du quantile-0.25 la valeur telle que 25% des observations de la variable lui sont inférieures. On les obtient avec quantile(), avec le deuxième argument qui doit être un vecteur contenant les pourcentages désirés :

quantile(pragmatique_df$duree, c(0.25, 0.33, 0.5, 0.66, 0.75))
  25%   33%   50%   66%   75% 
351.0 384.6 481.0 561.4 646.0 

Notons que le quantile 50% correspond à la médiane.

Finalement, on peut également obtenir plusieurs statistiques d’un coup en utilisant la fonction summary() :

summary(pragmatique_df$duree)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    0.0   351.0   481.0   571.1   646.0  2815.0 

Cette dernière peut même être appliquée à un tableau entier, auquel cas elle retournera un résumé pour chaque variable :

summary(pragmatique_df)
  id_marqueur      evenement       annee                          genre    
 Min.   :20001   DPU_SAL: 40   Min.   :2007   Débat public           :155  
 1st Qu.:20085   DPU_UDC: 26   1st Qu.:2007   Débat télévisé         : 70  
 Median :40077   DPU_MED: 22   Median :2008   Réunion professionnelle: 96  
 Mean   :34742   DPU_PRE: 21   Mean   :2011                                
 3rd Qu.:40158   DTV_DEM: 21   3rd Qu.:2017                                
 Max.   :40240   DPU_BIE: 20   Max.   :2018                                
                 (Other):171                                               
  timing_debut       timing_fin                     lemme    
 Min.   :  20296   Min.   :  20648   EVIDEMMENT        :111  
 1st Qu.:1196517   1st Qu.:1196719   SEMBLER           : 95  
 Median :2055657   Median :2056201   AVOIR L'IMPRESSION: 43  
 Mean   :2188817   Mean   :2189388   PARAÎTRE          : 23  
 3rd Qu.:2931688   3rd Qu.:2932249   APPAREMMENT       : 17  
 Max.   :6846140   Max.   :6847425   AVOIR L'AIR       : 14  
                                     (Other)           : 18  
             pos_tag                                type_morpho_syntaxique
 adverbe         :141   construction attributive à verbe copule: 64       
 locution verbale: 62   parenthétique                          : 29       
 verbe           :118   prédicat verbal à complément           : 85       
                        proposition complète                   :  2       
                        syntagme adverbial                     :141       
                                                                          
                                                                          
 position_du_marqueur_dans_l_uct position_de_l_uct_dans_le_tdp
 début   : 29                    début   : 29                 
 début*  : 56                    fin     : 47                 
 fin     : 16                    milieu  :182                 
 fin*    :  8                    totalité: 63                 
 milieu  :204                                                 
 totalité:  8                                                 
                                                              
   role_de_l_uct_dans_la_sequence       regard_avant_le_marqueur
 indéterminé      :233            allocutaire(s)    :142        
 initiatif        : 34            autre             : 53        
 réactif/évaluatif: 54            indéterminable    : 75        
                                  objet (symbolique): 47        
                                  tiers             :  3        
                                  yeux fermés       :  1        
                                                                
      regard_pendant_le_marqueur       regard_apres_le_marqueur
 allocutaire(s)    :147          allocutaire(s)    :158        
 autre             : 47          autre             : 41        
 indéterminable    : 75          indéterminable    : 70        
 objet (symbolique): 47          objet (symbolique): 47        
 tiers             :  4          tiers             :  5        
 yeux fermés       :  1                                        
                                                               
               presence_dun_geste                type_de_geste
 impossible à déterminer: 56      Deictic.Object        : 16  
 non                    :159      Deictic.Indeterminable: 13  
 oui                    :106      Deictic.Addressee     : 11  
                                  Meta.Cup              : 11  
                                  Emblem.Doubt-Shrug    :  9  
                                  (Other)               : 46  
                                  NAs                   :215  
           direction   source       polarite       duree        duree_cat  
 à l'intérieur  :129   AL: 13   négative:  7   Min.   :   0.0   court:108  
 à l’intérieur  :  4   ML:308   neutre  : 13   1st Qu.: 351.0   long :107  
 marqueur>portée:133            positive:301   Median : 481.0   moyen:106  
 portée<marqueur: 55                           Mean   : 571.1              
                                               3rd Qu.: 646.0              
                                               Max.   :2815.0              
                                                                           

On anticipe un peu (les graphiques viendront par la suite), mais voici la distribution de la variable duree:

ggplot(pragmatique_df, aes(x=duree)) +
  geom_histogram()
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

2.2 Statistiques uni-variées sur une variable catégorielle

Il existe nettement moins d’indicateurs usuels pour une variable catégorielle. Les principaux sont :

  • Les fréquences (absolues ou relatives) des différentes modalités.
  • Le mode, qui correspond à la modalité la plus fréquente.

Les modalités d’une variable catégorielle s’obtiennent avec unique() ou levels():

unique(pragmatique_df$lemme)
[1] SEMBLER             PARAÎTRE            AVOIR L'AIR        
[4] AVOIR L'IMPRESSION  DONNER L'IMPRESSION APPAREMMENT        
[7] EVIDEMMENT          MANIFESTEMENT       VISIBLEMENT        
9 Levels: APPAREMMENT AVOIR L'AIR AVOIR L'IMPRESSION ... VISIBLEMENT
levels(pragmatique_df$lemme)
[1] "APPAREMMENT"         "AVOIR L'AIR"         "AVOIR L'IMPRESSION" 
[4] "DONNER L'IMPRESSION" "EVIDEMMENT "         "MANIFESTEMENT"      
[7] "PARAÎTRE"            "SEMBLER"             "VISIBLEMENT"        

Pour obtenir les fréquences absolues d’une variable catégorielle, on utilise table():

table(pragmatique_df$lemme)

        APPAREMMENT         AVOIR L'AIR  AVOIR L'IMPRESSION DONNER L'IMPRESSION 
                 17                  14                  43                   5 
        EVIDEMMENT        MANIFESTEMENT            PARAÎTRE             SEMBLER 
                111                   5                  23                  95 
        VISIBLEMENT 
                  8 

Pour les fréquences relatives, on doit faire un calcul :

table(pragmatique_df$lemme) / sum(table(pragmatique_df$lemme))

        APPAREMMENT         AVOIR L'AIR  AVOIR L'IMPRESSION DONNER L'IMPRESSION 
         0.05295950          0.04361371          0.13395639          0.01557632 
        EVIDEMMENT        MANIFESTEMENT            PARAÎTRE             SEMBLER 
         0.34579439          0.01557632          0.07165109          0.29595016 
        VISIBLEMENT 
         0.02492212 

Le mode s’obtient avec la fonction Mode() (de DescTools) :

Mode(pragmatique_df$lemme)
[1] EVIDEMMENT 
attr(,"freq")
[1] 111
9 Levels: APPAREMMENT AVOIR L'AIR AVOIR L'IMPRESSION ... VISIBLEMENT

2.3 Statistiques bi-variées

Les statistiques bi-variées que nous allons voir sont peu nombreuses.

Entre deux variables numériques, on peut utiliser la covariance ou la corrélation, avec cov() et cor() :

cov(pragmatique_df$timing_debut, pragmatique_df$duree)
[1] 18796953
cor(pragmatique_df$timing_debut, pragmatique_df$duree)
[1] 0.03582446

Il y a un faible lien positif entre le timing du début de la durée.

Entre deux variables catégorielles, on peut afficher le tableau croisé avec table() :

table(pragmatique_df$lemme, pragmatique_df$genre)
                     
                      Débat public Débat télévisé Réunion professionnelle
  APPAREMMENT                    5              1                      11
  AVOIR L'AIR                    6              2                       6
  AVOIR L'IMPRESSION            15              6                      22
  DONNER L'IMPRESSION            0              0                       5
  EVIDEMMENT                    60             34                      17
  MANIFESTEMENT                  2              3                       0
  PARAÎTRE                       9              8                       6
  SEMBLER                       54             14                      27
  VISIBLEMENT                    4              2                       2

2.4 Gestion des valeurs manquantes

Il est important de noter que les fonctions de statistiques uni- et bi-variées ne gèrent pas les valeurs manquantes. Par défaut, elles retournent NA. Pour les faire fonctionner, il faut ajouter l’argument na.rm=TRUE :

test = c(4, 5, NA, 8)
mean(test)
[1] NA
mean(test, na.rm=TRUE)
[1] 5.666667

3 Utilisation dans le tidyverse

3.1 Calcule d’indices avec mutate()

Le calcul d’indice statistiques dans le tidyverse peut intervenir dans des contextes différents.

Si l’on utilise aucune agrégation ou groupes (voir Section 3.3) et que l’on utilise directement mutate(), les fonctions de statistiques vont calculer l’indice sur l’ensemble du jeu de données, et retourner la même valeur pour chaque observation :

pragmatique_df = pragmatique_df %>%
  mutate(m_duree=mean(duree))
pragmatique_df %>%
  select(id_marqueur, lemme, duree, m_duree)
# A tibble: 321 × 4
   id_marqueur lemme              duree m_duree
         <dbl> <fct>              <dbl>   <dbl>
 1       20001 SEMBLER              186    571.
 2       20002 PARAÎTRE             249    571.
 3       20003 PARAÎTRE             146    571.
 4       20004 PARAÎTRE             814    571.
 5       20005 PARAÎTRE             174    571.
 6       20006 PARAÎTRE              55    571.
 7       20007 AVOIR L'AIR          387    571.
 8       20008 AVOIR L'AIR          159    571.
 9       20009 AVOIR L'AIR          316    571.
10       20010 AVOIR L'IMPRESSION  1176    571.
# ℹ 311 more rows
AstuceUne application : la normalisation des variables

Calculer des indices constants sur une colonne peut parfois être utile : on peut s’en servir par exemple pour normaliser nos variables (en construisant deux colonnes auxiliaires pour la moyenne et l’écart-type) :

pragmatique_df = pragmatique_df %>%
  mutate(m_duree=mean(duree), sd_duree=sd(duree), duree_norm=(duree - m_duree) / sd_duree)
pragmatique_df %>%
  select(id_marqueur, lemme, duree, m_duree, sd_duree, duree_norm)
# A tibble: 321 × 6
   id_marqueur lemme              duree m_duree sd_duree duree_norm
         <dbl> <fct>              <dbl>   <dbl>    <dbl>      <dbl>
 1       20001 SEMBLER              186    571.     377.     -1.02 
 2       20002 PARAÎTRE             249    571.     377.     -0.854
 3       20003 PARAÎTRE             146    571.     377.     -1.13 
 4       20004 PARAÎTRE             814    571.     377.      0.644
 5       20005 PARAÎTRE             174    571.     377.     -1.05 
 6       20006 PARAÎTRE              55    571.     377.     -1.37 
 7       20007 AVOIR L'AIR          387    571.     377.     -0.488
 8       20008 AVOIR L'AIR          159    571.     377.     -1.09 
 9       20009 AVOIR L'AIR          316    571.     377.     -0.676
10       20010 AVOIR L'IMPRESSION  1176    571.     377.      1.60 
# ℹ 311 more rows

Il existe cependant un raccourci pour cela, avec scale(), qui fait exactement la même chose :

pragmatique_df = pragmatique_df %>%
  mutate(duree_norm2=scale(duree))
pragmatique_df %>%
  select(id_marqueur, lemme, duree, m_duree, sd_duree, duree_norm, duree_norm2)
# A tibble: 321 × 7
   id_marqueur lemme           duree m_duree sd_duree duree_norm duree_norm2[,1]
         <dbl> <fct>           <dbl>   <dbl>    <dbl>      <dbl>           <dbl>
 1       20001 SEMBLER           186    571.     377.     -1.02           -1.02 
 2       20002 PARAÎTRE          249    571.     377.     -0.854          -0.854
 3       20003 PARAÎTRE          146    571.     377.     -1.13           -1.13 
 4       20004 PARAÎTRE          814    571.     377.      0.644           0.644
 5       20005 PARAÎTRE          174    571.     377.     -1.05           -1.05 
 6       20006 PARAÎTRE           55    571.     377.     -1.37           -1.37 
 7       20007 AVOIR L'AIR       387    571.     377.     -0.488          -0.488
 8       20008 AVOIR L'AIR       159    571.     377.     -1.09           -1.09 
 9       20009 AVOIR L'AIR       316    571.     377.     -0.676          -0.676
10       20010 AVOIR L'IMPRES…  1176    571.     377.      1.60            1.60 
# ℹ 311 more rows

On peut s’assurer que les deux variables sont bien normalisées avec :

mean(pragmatique_df$duree_norm)
[1] 6.637128e-16
sd(pragmatique_df$duree_norm)
[1] 1
mean(pragmatique_df$duree_norm2)
[1] 3.908262e-17
sd(pragmatique_df$duree_norm2)
[1] 1

3.2 Utilisation de summarize() et reframe()

Si la fonction ne retourne qu’un résultat, il est souvent plus judicieux d’utiliser la fonction summarize() (ou summarise()), qui applique l’indice et combine toutes les observations en une seule :

pragmatique_df %>%
  summarize(m_duree=mean(duree))
# A tibble: 1 × 1
  m_duree
    <dbl>
1    571.

On peut également l’utiliser pour créer plusieurs indices (la fonction n() compte le nombre d’observations) :

pragmatique_df %>%
  summarize(n_observations = n(), m_duree=mean(duree), med_duree=median(duree), sd_duree=sd(duree))
# A tibble: 1 × 4
  n_observations m_duree med_duree sd_duree
           <int>   <dbl>     <dbl>    <dbl>
1            321    571.       481     377.

Si l’on veut utiliser une fonction qui retourne plusieurs résultats, on utilisera plutôt reframe() :

pragmatique_df %>% 
  reframe(quantiles = c("P25", "P50", "P75"),
          q_duree=quantile(duree, c(0.25, 0.5, 0.75)))
# A tibble: 3 × 2
  quantiles q_duree
  <chr>       <dbl>
1 P25           351
2 P50           481
3 P75           646

3.3 Définir des groupes et la logique du “Split-Apply-Combine”

La puissance de summarize() devient plus évidente lorsque l’on souhaite faire des statistiques par groupe. La logique devient alors celle du “Split-Apply-Combine”, qui effectue les opérations suivantes :

  1. Split : le jeu de données est divisé en groupes selon une ou plusieurs variables.
  2. Apply : une fonction est appliquée à chaque groupe pour calculer des statistiques ou effectuer des transformations.
  3. Combine : les résultats de chaque groupe sont combinés pour former un nouveau jeu de données

L’opération de split, c’est-à-dire celle de définir les groupes, se fait en amont des deux autres grâce à la fonction group_by() :

pragmatique_df %>%
  group_by(lemme)
# A tibble: 321 × 26
# Groups:   lemme [9]
   id_marqueur evenement annee genre       timing_debut timing_fin lemme pos_tag
         <dbl> <fct>     <dbl> <fct>              <dbl>      <dbl> <fct> <fct>  
 1       20001 DPU_UDC    2007 Débat publ…       804366     804552 SEMB… verbe  
 2       20002 DPU_REC    2007 Débat publ…      1352035    1352284 PARA… verbe  
 3       20003 DPU_UDC    2007 Débat publ…      1888187    1888333 PARA… verbe  
 4       20004 DTV_SM1    2007 Débat télé…       340280     341094 PARA… verbe  
 5       20005 DTV_SM2    2013 Débat télé…       880398     880572 PARA… verbe  
 6       20006 REU_BL1    2017 Réunion pr…      2729947    2730002 PARA… verbe  
 7       20007 DPU_MED    2008 Débat publ…      2878433    2878820 AVOI… locuti…
 8       20008 DTV_DEM    2007 Débat télé…      3199465    3199624 AVOI… locuti…
 9       20009 DTV_VEH    2007 Débat télé…       463064     463380 AVOI… locuti…
10       20010 DPU_BIE    2009 Débat publ…      2384187    2385363 AVOI… locuti…
# ℹ 311 more rows
# ℹ 18 more variables: type_morpho_syntaxique <fct>,
#   position_du_marqueur_dans_l_uct <fct>, position_de_l_uct_dans_le_tdp <fct>,
#   role_de_l_uct_dans_la_sequence <fct>, regard_avant_le_marqueur <fct>,
#   regard_pendant_le_marqueur <fct>, regard_apres_le_marqueur <fct>,
#   presence_dun_geste <fct>, type_de_geste <fct>, direction <fct>,
#   source <fct>, polarite <fct>, duree <dbl>, duree_cat <fct>, …

On peut même utiliser plusieurs variables categorielles pour définir des groupes plus fins :

pragmatique_df %>%
  group_by(lemme, genre)
# A tibble: 321 × 26
# Groups:   lemme, genre [24]
   id_marqueur evenement annee genre       timing_debut timing_fin lemme pos_tag
         <dbl> <fct>     <dbl> <fct>              <dbl>      <dbl> <fct> <fct>  
 1       20001 DPU_UDC    2007 Débat publ…       804366     804552 SEMB… verbe  
 2       20002 DPU_REC    2007 Débat publ…      1352035    1352284 PARA… verbe  
 3       20003 DPU_UDC    2007 Débat publ…      1888187    1888333 PARA… verbe  
 4       20004 DTV_SM1    2007 Débat télé…       340280     341094 PARA… verbe  
 5       20005 DTV_SM2    2013 Débat télé…       880398     880572 PARA… verbe  
 6       20006 REU_BL1    2017 Réunion pr…      2729947    2730002 PARA… verbe  
 7       20007 DPU_MED    2008 Débat publ…      2878433    2878820 AVOI… locuti…
 8       20008 DTV_DEM    2007 Débat télé…      3199465    3199624 AVOI… locuti…
 9       20009 DTV_VEH    2007 Débat télé…       463064     463380 AVOI… locuti…
10       20010 DPU_BIE    2009 Débat publ…      2384187    2385363 AVOI… locuti…
# ℹ 311 more rows
# ℹ 18 more variables: type_morpho_syntaxique <fct>,
#   position_du_marqueur_dans_l_uct <fct>, position_de_l_uct_dans_le_tdp <fct>,
#   role_de_l_uct_dans_la_sequence <fct>, regard_avant_le_marqueur <fct>,
#   regard_pendant_le_marqueur <fct>, regard_apres_le_marqueur <fct>,
#   presence_dun_geste <fct>, type_de_geste <fct>, direction <fct>,
#   source <fct>, polarite <fct>, duree <dbl>, duree_cat <fct>, …

Une fois des groupes formés, on peut utiliser mutate() pour passer à l’étape apply. Les indices sont ainsi calculés indépendamment sur chaque groupe :

pragmatique_df %>%
  group_by(lemme, genre) %>%
  mutate(m_duree=mean(duree), sd_duree=sd(duree)) %>%
  select(genre, lemme, m_duree, sd_duree)
# A tibble: 321 × 4
# Groups:   lemme, genre [24]
   genre                   lemme              m_duree sd_duree
   <fct>                   <fct>                <dbl>    <dbl>
 1 Débat public            SEMBLER               573.    339. 
 2 Débat public            PARAÎTRE              317.     98.4
 3 Débat public            PARAÎTRE              317.     98.4
 4 Débat télévisé          PARAÎTRE              385.    200. 
 5 Débat télévisé          PARAÎTRE              385.    200. 
 6 Réunion professionnelle PARAÎTRE              367     299. 
 7 Débat public            AVOIR L'AIR           652     737. 
 8 Débat télévisé          AVOIR L'AIR           238.    111. 
 9 Débat télévisé          AVOIR L'AIR           238.    111. 
10 Débat public            AVOIR L'IMPRESSION   1127.    531. 
# ℹ 311 more rows

C’est avec summarize() (ou reframe()) que l’apply est suivi d’un combine : le calcul est effectué sur chaque groupe et le résultat est combiné par groupe (d’ailleurs, la dernière granularité du groupe disparait) :

pragmatique_df %>%
  group_by(lemme, genre) %>%
  summarize(n_obs = n(), m_duree=mean(duree), sd_duree=sd(duree))
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by lemme and genre.
ℹ Output is grouped by lemme.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(lemme, genre))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.
# A tibble: 24 × 5
# Groups:   lemme [9]
   lemme               genre                   n_obs m_duree sd_duree
   <fct>               <fct>                   <int>   <dbl>    <dbl>
 1 APPAREMMENT         Débat public                5    521      138.
 2 APPAREMMENT         Débat télévisé              1    815       NA 
 3 APPAREMMENT         Réunion professionnelle    11    514      182.
 4 AVOIR L'AIR         Débat public                6    652      737.
 5 AVOIR L'AIR         Débat télévisé              2    238.     111.
 6 AVOIR L'AIR         Réunion professionnelle     6    288.     138.
 7 AVOIR L'IMPRESSION  Débat public               15   1127.     531.
 8 AVOIR L'IMPRESSION  Débat télévisé              6    911.     607.
 9 AVOIR L'IMPRESSION  Réunion professionnelle    22    873.     440.
10 DONNER L'IMPRESSION Réunion professionnelle     5   1399.     556.
# ℹ 14 more rows

Si les groupes ont été définis avec plusieurs variables, un enchaînement de summarize() va donner des statistiques de plus en plus grossières :

gr_1 = pragmatique_df %>%
  group_by(lemme, genre) %>%
  summarize(n_obs=n(), m_duree=mean(duree)) 
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by lemme and genre.
ℹ Output is grouped by lemme.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(lemme, genre))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.
gr_2 = gr_1 %>%
  summarize(n_obs=sum(n_obs), m_duree=mean(m_duree)) 
gr_1
# A tibble: 24 × 4
# Groups:   lemme [9]
   lemme               genre                   n_obs m_duree
   <fct>               <fct>                   <int>   <dbl>
 1 APPAREMMENT         Débat public                5    521 
 2 APPAREMMENT         Débat télévisé              1    815 
 3 APPAREMMENT         Réunion professionnelle    11    514 
 4 AVOIR L'AIR         Débat public                6    652 
 5 AVOIR L'AIR         Débat télévisé              2    238.
 6 AVOIR L'AIR         Réunion professionnelle     6    288.
 7 AVOIR L'IMPRESSION  Débat public               15   1127.
 8 AVOIR L'IMPRESSION  Débat télévisé              6    911.
 9 AVOIR L'IMPRESSION  Réunion professionnelle    22    873.
10 DONNER L'IMPRESSION Réunion professionnelle     5   1399.
# ℹ 14 more rows
gr_2
# A tibble: 9 × 3
  lemme               n_obs m_duree
  <fct>               <int>   <dbl>
1 APPAREMMENT            17    617.
2 AVOIR L'AIR            14    393.
3 AVOIR L'IMPRESSION     43    970.
4 DONNER L'IMPRESSION     5   1399.
5 EVIDEMMENT            111    476.
6 MANIFESTEMENT           5    652.
7 PARAÎTRE               23    356.
8 SEMBLER                95    548.
9 VISIBLEMENT             8    553.

Le besoin de compter les effectifs par groupe (group_by(...) %>% summarize(n = n())) est tellement fréquent en statistiques qu’il existe une fonction raccourci dédiée : count(). C’est l’équivalent Tidyverse de la fonction table() que nous avons vue plus tôt, mais elle retourne un tibble prêt à l’emploi (et permet de classer les observations) :

pragmatique_df %>%
  count(lemme, sort=TRUE) %>%
  mutate(freq_rel = n / sum(n))
# A tibble: 9 × 3
  lemme                   n freq_rel
  <fct>               <int>    <dbl>
1 EVIDEMMENT            111   0.346 
2 SEMBLER                95   0.296 
3 AVOIR L'IMPRESSION     43   0.134 
4 PARAÎTRE               23   0.0717
5 APPAREMMENT            17   0.0530
6 AVOIR L'AIR            14   0.0436
7 VISIBLEMENT             8   0.0249
8 DONNER L'IMPRESSION     5   0.0156
9 MANIFESTEMENT           5   0.0156

Finalement, la fonction reframe() nous permet d’obtenir plusieurs valeurs par groupe, et duplique donc le nombre de lignes par le nombre de résultats :

pragmatique_df %>%
  group_by(lemme) %>%
  reframe(quantiles = c("P25", "P50", "P75"),
          q_duree=quantile(duree, c(0.25, 0.5, 0.75)))
# A tibble: 27 × 3
   lemme               quantiles q_duree
   <fct>               <chr>       <dbl>
 1 APPAREMMENT         P25          407 
 2 APPAREMMENT         P50          525 
 3 APPAREMMENT         P75          646 
 4 AVOIR L'AIR         P25          252.
 5 AVOIR L'AIR         P50          346.
 6 AVOIR L'AIR         P75          386.
 7 AVOIR L'IMPRESSION  P25          618.
 8 AVOIR L'IMPRESSION  P50          816 
 9 AVOIR L'IMPRESSION  P75         1355 
10 DONNER L'IMPRESSION P25         1110 
# ℹ 17 more rows