POL6022 - Méthodes quantitatives avancées

Evelyne Brie

Hiver 2026

Données manquantes

Dans ce laboratoire, nous allons : (1) identifier les valeurs manquantes dans les colonnes, (2) rechercher des modèles de données manquantes et (3) effectuer une suppression de type listwise.

Fonctions pertinentes : missing_plot(), missing_pairs(), na.omit(), drop_na().

1. Importation des données

Nous commençons par importer un jeu de données provenant du World Value Survey, une enquête menée chaque année dans plus de 100 pays depuis 1981. Elle comprend des questions sur le statut socio-économique et des questions sur les attitudes envers divers enjeux.

# Définir le répertoire de travail
setwd(dirname(rstudioapi::getSourceEditorContext()$path))

# Chargement des données
wvs <- read.csv("WVS_subset.csv")

# Affichage des noms de colonnes
colnames(wvs)
##  [1] "X"               "version"         "doi"             "A_WAVE"         
##  [5] "A_YEAR"          "A_STUDY"         "B_COUNTRY"       "B_COUNTRY_ALPHA"
##  [9] "Q46"             "Q47"             "Q48"             "Q49"            
## [13] "Q50"             "Q51"             "Q52"             "Q53"            
## [17] "Q54"             "Q55"             "Q56"             "X003R"          
## [21] "X003R2"          "Q263"            "Q264"            "Q265"           
## [25] "Q266"            "Q267"            "Q268"            "Q269"           
## [29] "Q270"            "Q271"            "Q272"            "Q273"           
## [33] "Q274"            "Q275"            "Q275A"           "Q275R"          
## [37] "Q276"            "Q276A"           "Q276R"           "Q277"           
## [41] "Q277A"           "Q277R"           "Q278"            "Q278A"          
## [45] "Q278R"           "Q279"            "Q280"            "Q281"           
## [49] "Q282"            "Q283"            "Q284"            "Q285"           
## [53] "Q286"            "Q287"            "Q288"            "Q288R"          
## [57] "Q289"            "Q289CS9"         "Q290"

Le livre de codes est disponible sur Studium. Vous remarquerez que les 7 premières colonnes affichent des informations sur la vague, le pays et l’année de l’étude. Les questions Q46 à Q47 sont relatives au bonheur et au bien-être. Les autres questions offrent des aperçus sur le statut socio-économique des répondants. Il s’agit d’un sous-ensemble du jeu de données WVS original que j’ai créé pour les besoins de ce laboratoire — les données complètes sont disponibles gratuitement en ligne si vous êtes intéressé.

# Affichage de la première observation
head(wvs,1)
##      X            version                       doi A_WAVE A_YEAR A_STUDY
## 1 1659 4-0-0 (2022-05-23) doi.org/10.14281/18241.18      7   2018       2
##   B_COUNTRY B_COUNTRY_ALPHA Q46 Q47 Q48 Q49 Q50 Q51 Q52 Q53 Q54 Q55 Q56 X003R
## 1       156             CHN   2   2   5   5   5   4   4   4   4   4   1     3
##   X003R2 Q263 Q264 Q265 Q266 Q267 Q268 Q269 Q270 Q271 Q272 Q273 Q274 Q275 Q275A
## 1      2    1   NA   NA   NA   NA   NA   NA    3    1 2870    1    1   NA    NA
##   Q275R Q276 Q276A Q276R Q277 Q277A Q277R Q278 Q278A Q278R Q279 Q280 Q281 Q282
## 1    NA   NA    NA    NA   NA    NA    NA   NA    NA    NA   NA   NA   NA   NA
##   Q283 Q284 Q285 Q286 Q287 Q288 Q288R Q289   Q289CS9   Q290
## 1   NA   NA    2    1    3    4     2    0 100000020 156001

Nous voyons déjà que nous devrons gérer un tas de NA dans ce jeu de données. Pour ce premier répondant, par exemple, les questions Q264 à Q269 sont manquantes. Ces questions sont relatives au statut de citoyenneté et aux antécédents d’immigration parentale. Nous voyons également que les questions Q275 à Q284 sont manquantes. Ces questions sont relatives aux antécédents éducatifs et professionnels.

Regardons les trois premiers répondants, qui sont tous de Chine et ont tous répondu à l’enquête en 2018.

# Affichage des trois premières observations
head(wvs,3)
##      X            version                       doi A_WAVE A_YEAR A_STUDY
## 1 1659 4-0-0 (2022-05-23) doi.org/10.14281/18241.18      7   2018       2
## 2 1660 4-0-0 (2022-05-23) doi.org/10.14281/18241.18      7   2018       2
## 3 1661 4-0-0 (2022-05-23) doi.org/10.14281/18241.18      7   2018       2
##   B_COUNTRY B_COUNTRY_ALPHA Q46 Q47 Q48 Q49 Q50 Q51 Q52 Q53 Q54 Q55 Q56 X003R
## 1       156             CHN   2   2   5   5   5   4   4   4   4   4   1     3
## 2       156             CHN   1   1  10  10  10   4   4   4   4   4   1     4
## 3       156             CHN   1   1  10  10  10   4   4   4   4   4   1     6
##   X003R2 Q263 Q264 Q265 Q266 Q267 Q268 Q269 Q270 Q271 Q272 Q273 Q274 Q275 Q275A
## 1      2    1   NA   NA   NA   NA   NA   NA    3    1 2870    1    1   NA    NA
## 2      3    1   NA   NA   NA   NA   NA   NA    6    1 2870    1    2    1    NA
## 3      3    1   NA   NA   NA   NA   NA   NA    1    1 2870    5    2    3    NA
##   Q275R Q276 Q276A Q276R Q277 Q277A Q277R Q278 Q278A Q278R Q279 Q280 Q281 Q282
## 1    NA   NA    NA    NA   NA    NA    NA   NA    NA    NA   NA   NA   NA   NA
## 2     1    1    NA     1    0    NA     1    0    NA     1    1    3    8    9
## 3     2   NA    NA    NA    0    NA     1    0    NA     1    4   NA   NA   NA
##   Q283 Q284 Q285 Q286 Q287 Q288 Q288R Q289   Q289CS9   Q290
## 1   NA   NA    2    1    3    4     2    0 100000020 156001
## 2    9   NA    2    3   NA    3     1    0 100000020 156001
## 3    0    1    2    1    3    6     2    0 100000020 156001

Ici, il semble que les questions Q264 à Q269 soient également manquantes pour les deuxième et troisième répondants, mais que les questions Q275 à Q284 soient (principalement) non manquantes. Cela pourrait signifier que pour diverses raisons, les enquêteurs n’ont pas posé les questions Q264 à Q269 dans ce pays particulier. Ce n’est qu’une intuition — le test que nous ferons ci-dessous nous permettra de vérifier cela.

2. Identifier les valeurs manquantes

La prochaine chose que nous voulons faire est d’afficher la distribution des valeurs manquantes dans les colonnes. Tout d’abord, chargeons les packages nécessaires.

# Chargement des packages nécessaires
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.6
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.1     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.2
## ✔ purrr     1.2.0     
## ── 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(finalfit)

Pourquoi chargeons-nous le package tidyverse ? Parce que nous utiliserons %>% dans les étapes suivantes.

 

Note rapide sur %>%

Ceci n’est pas une pipe… ou l’est-ce ? Le symbole %>% est en fait l’opérateur pipe du package magrittr, qui est inclus dans le tidyverse (une sorte de méta-package).

Voici comment cela fonctionne :

# Affichage du résumé de la variable Q46 en utilisant le R de base
summary(wvs$Q46)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.000   1.000   2.000   1.877   2.000   4.000     142
# Affichage du résumé de la variable Q46 en utilisant l'opérateur pipe
wvs$Q46 %>%
  summary()
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.000   1.000   2.000   1.877   2.000   4.000     142

Ici, l’opérateur pipe “envoie” wvs$Q46 dans la fonction summary().

Nous pouvons également ajouter d’autres fonctions, comme indiqué ci-dessous :

# Affichage du résumé de la variable Q46 en utilisant l'opérateur pipe 
# tout en gardant uniquement les répondants chinois
wvs %>%
  subset(B_COUNTRY_ALPHA=="CHN", select="Q46") %>% 
  summary() 
##       Q46       
##  Min.   :1.000  
##  1st Qu.:1.000  
##  Median :2.000  
##  Mean   :1.851  
##  3rd Qu.:2.000  
##  Max.   :4.000  
##  NA's   :1

Dans l’ensemble, c’est un opérateur vraiment puissant qui peut rendre votre code beaucoup plus efficace.

 

Utilisons la fonction missing_plot() pour afficher l’emplacement des NA dans notre jeu de données. Ici, nous afficherons les NA par question, pour chaque observation. Les bandes bleu clair représentent les valeurs manquantes.

# Affichage des valeurs manquantes par colonne, pour chaque observation
wvs %>%
  missing_plot()

J’ai le soupçon que les questions Q264 à Q269 pourraient être manquantes pour tous les répondants chinois. Testons cela en sous-ensemble du jeu de données pour n’inclure que les répondants pour lesquels la variable B_COUNTRY_ALPHA est égale à CHN.

# Chargement des packages nécessaires
library(tidyverse)
library(finalfit)

# Affichage des valeurs manquantes par colonne, pour chaque observation
wvs %>%
  subset(B_COUNTRY_ALPHA=="CHN") %>% 
  missing_plot()

Nous pouvons donc conclure que dans l’échantillon chinois, 没有问这些问题 (ces questions n’ont pas été posées). Nous remarquons également que quatre autres questions plus loin dans le jeu de données sont manquantes pour tous les répondants chinois. C’est vraiment utile à savoir !

3. Rechercher des tendances

Examinons maintenant si certaines variables peuvent nous aider à trouver des tendances de valeurs manquantes pour les variables où les répondants de chaque pays auraient pu répondre, mais certains ont préféré ne pas le faire. Nous pouvons examiner une question que les gens n’aiment généralement pas répondre, par exemple celle-ci :

Q287 : Les gens se décrivent parfois comme appartenant à la classe ouvrière, à la classe moyenne, ou à la classe supérieure ou inférieure. Vous décririez-vous comme appartenant à :

1. Classe supérieure

2. Classe moyenne supérieure

3. Classe moyenne inférieure

4. Classe ouvrière

5. Classe inférieure

L’écart de revenus
L’écart de revenus

Voyons quels sont les tendances de réponses manquantes par pays.

# Chargement des packages nécessaires
library(tidyverse)
library(finalfit)

# Affichage d'un test de diagnostic du pays comme déterminant
# des valeurs manquantes pour Q287
explanatory <- "B_COUNTRY_ALPHA"
dependent <- "Q287"
wvs %>% 
  missing_pairs(dependent, explanatory)
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the finalfit package.
##   Please report the issue at <https://github.com/ewenharrison/finalfit/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 656 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Removed 656 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

Ici, nous voyons que les répondants des Pays-Bas ont beaucoup plus de valeurs manquantes que les répondants d’autres pays. Il est important de savoir ce que sont réellement les valeurs manquantes — vous trouverez ces informations dans les métadonnées de chaque jeu de données.

Ici, le rapport de variable spécifie que les valeurs manquantes WVS peuvent être : ne sait pas, pas de réponse, pas demandé ou manquant/non disponible. C’est-à-dire que nous ne pouvons pas dire à partir de ce graphique pourquoi nous observons plus de données manquantes aux Pays-Bas, nous savons juste que c’est le cas.

4. Effectuer une suppression de type listwise

Il existe de nombreuses façons de traiter les NA dans R. La manière la plus basique suppose que les observations sont manquantes complètement au hasard (MCAR). Note : si vous êtes intéressé par ce qu’il faut faire sous les hypothèses MNAR et MAR, je recommande la ressource suivante : https://argoshare.is.ed.ac.uk/healthyr_book/handling-missing-data-mar.html

Disons que nous voulions supprimer TOUTES les lignes contenant des NA (pour n’importe quelle variable) de notre jeu de données. En d’autres termes, si une colonne est vide pour un répondant donné, nous supprimons ce répondant du jeu de données. C’est très facile à faire en utilisant la fonction na.omit().

# Effectuer une suppression par ligne
wvs_noNas <- na.omit(wvs)

# Regarder les dimensions de notre nouveau jeu de données
dim(wvs_noNas)
## [1] 1218   59

Bon… on a un problème. Il semble qu’on ait supprimé l’écrasante majorité de notre jeu de données (c’est-à-dire 13 867 répondants sur 15 085 au total). Peut-être qu’avoir des valeurs manquantes dans certaines de ces variables n’aurait eu aucun impact sur notre projet de recherche de toute façon. Soyons un peu plus conservateurs et supprimons uniquement les répondants qui ont une valeur manquante pour une variable, disons Q287.

# Effectuer une suppression par ligne 
newWVS <- wvs %>%
          drop_na("Q287") # Suppression uniquement des répondants qui ont un NA pour Q287

# Regarder les dimensions de notre nouveau jeu de données
dim(newWVS)
## [1] 14429    59

C’est un peu plus raisonnable. Mais rappelez-vous : ce qui compte le plus est la justification théorique pour laquelle vous supprimez les NA.

Exercices

Session de pratique générale

Vous aurez remarqué que le matériel de lab de cette semaine est hyper condensé (i.e. quelques fonctions seulement). Utilisons notre temps ensemble pour faire un test plus général.

En utilisant le jeu de données WVS et le livre de codes associé…

  1. Créez une variable indicatrice appelée Happy qui prend une valeur de 1 lorsque les répondants déclarent être très heureux ou plutôt heureux à Q46. En regardant la distribution de cette variable, diriez-vous que la plupart des gens sont heureux, ou non ?
# Création d'une nouvelle variable indicatrice
wvs$Happy <- NA
wvs$Happy[wvs$Q46==1 | wvs$Q46==2] <- 1
wvs$Happy[wvs$Q46==3 | wvs$Q46==4] <- 0

# Vérification de la distribution de Happy comme test de cohérence
table(wvs$Happy)
## 
##     0     1 
##  1710 13233
  1. En utilisant les fonctions prop.table() et table(), créez un tableau avec la distribution de la variable Happy par pays, en pourcentage par pays (wvs$B_COUNTRY_ALPHA). Quel pays est le plus heureux ? Quel pays est le moins heureux ?
# Création d'un prop.table avec pourcentage par ligne (c'est l'argument 1)
prop.table(table(wvs$B_COUNTRY_ALPHA,wvs$Happy),1)
##      
##                0          1
##   BRA 0.09914040 0.90085960
##   CAN 0.13613738 0.86386262
##   CHN 0.10774300 0.89225700
##   DEU 0.10848126 0.89151874
##   NLD 0.08546169 0.91453831
##   USA 0.12519320 0.87480680
  1. Créez une variable continue appelée Safe qui prend la valeur moyenne de la réponse d’un répondant aux questions Q51 à Q55.
# Création de la variable continue Safe
wvs$Safe <- NA
wvs$Safe <- (wvs$Q51+wvs$Q52+wvs$Q53+wvs$Q54+wvs$Q55)/5

# Vérification du résumé comme test de cohérence
summary(wvs$Safe)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.000   3.600   4.000   3.668   4.000   4.000     234
  1. En utilisant la fonction t.test(), effectuez un test t qui compare la valeur de Safe pour les citoyens du Canada et des États-Unis.
# Exécution d'un t.test()
t.test(wvs$Safe[wvs$B_COUNTRY_ALPHA=="CAN"],wvs$Safe[wvs$B_COUNTRY_ALPHA=="USA"])
## 
##  Welch Two Sample t-test
## 
## data:  wvs$Safe[wvs$B_COUNTRY_ALPHA == "CAN"] and wvs$Safe[wvs$B_COUNTRY_ALPHA == "USA"]
## t = 5.1626, df = 5456.9, p-value = 2.522e-07
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.0462386 0.1028538
## sample estimates:
## mean of x mean of y 
##  3.617670  3.543124