---
title: "Lire un dictionnaire de données, les labels et les types"
---
```{r}
#| label: setup-chapitre
#| include: false
suppressPackageStartupMessages({
library(dplyr)
library(tidyr)
library(ggplot2)
})
```
::: {.callout-important title="Question de départ"}
Si une colonne contient les valeurs `1`, `2`, `3`, `98` et `99`, comment savoir si elle représente une quantité, une catégorie ordonnée, « ne sait pas » ou un refus de répondre ?
:::
## Objectifs d'apprentissage
À la fin de ce chapitre, vous saurez :
- distinguer nom de variable, label de variable, valeur et label de valeur ;
- utiliser le questionnaire et le dictionnaire comme partie intégrante de l'analyse ;
- distinguer **type conceptuel**, **type de stockage** et **classe R** ;
- comprendre un objet `haven_labelled` sans le convertir trop tôt ;
- inspecter les labels avec `{labelled}` et `{haven}` ;
- reconnaître les codes spéciaux : « sans objet », « ne sait pas », « refus » ;
- décider quand convertir une variable en facteur et quand conserver sa version codée ;
- produire une première fiche de variables avant tout nettoyage.
## Prérequis
Il faut savoir importer un fichier, utiliser `class()`, `str()`, `glimpse()` et `count()`.
## Une colonne n'est pas auto-documentée
Le fichier de données peut contenir :
```text
diplome
4
6
3
98
4
99
```
Sans documentation, plusieurs interprétations sont possibles. Le code `6` pourrait signifier « Bac+5 », une note sur 10, une catégorie de PCS ou autre chose. Les valeurs `98` et `99` peuvent être des réponses réelles, des codes spéciaux ou des erreurs.
C'est pourquoi l'analyse d'enquête repose sur un ensemble de documents :
- le **questionnaire** ;
- le **dictionnaire de variables** ou *codebook* ;
- éventuellement le manuel d'enquête, les filtres, consignes aux enquêteurs et notes méthodologiques ;
- le fichier de microdonnées lui-même.
Le chapitre 1 insistait sur ce point : le fichier n'est qu'une partie de l'enquête. Ici, nous transformons ce principe en routine de travail.
## Les quatre éléments à ne pas confondre
Prenons la variable `diplome` du jeu `EnquêteR`.
### Nom de variable
```text
diplome
```
C'est le nom utilisé dans le code.
### Label de variable
```text
Niveau de diplôme le plus élevé obtenu
```
Il donne une formulation plus lisible et plus proche du questionnaire.
### Valeur ou code
```text
1, 2, 3, ..., 98, 99
```
C'est ce qui est stocké dans les lignes du fichier.
### Label de valeur
```text
1 = Sans diplôme
2 = Brevet / CEP
3 = CAP / BEP
...
98 = Ne sait pas
99 = Refus
```
Un format statistique comme Stata ou SPSS peut stocker ces associations directement avec la variable. Un CSV, lui, n'embarque généralement pas ce dictionnaire.
::: {.callout-note title="À retenir"}
Le nom sert au code ; le label sert à la lecture ; le code est stocké ; le label de valeur explique le code. Les quatre informations peuvent coexister sans être interchangeables.
:::
## Le dictionnaire fourni avec le livre
Le fichier :
```text
data/documentation/dictionnaire_variables.xlsx
```
contient trois feuilles :
- `Variables` : description de chaque variable ;
- `Modalites` : détail des codes et libellés ;
- `Anomalies pedagogiques` : anomalies volontairement introduites dans le fichier brut.
Une version CSV de la feuille principale est également fournie :
```{r}
dictionnaire <- readr::read_csv(
"data/documentation/dictionnaire_variables.csv",
show_col_types = FALSE
)
dplyr::glimpse(dictionnaire)
```
Quelques colonnes importantes :
- `variable` : nom informatique ;
- `libelle` : définition lisible ;
- `type_conceptuel` : nature substantive ;
- `type_brut` : représentation attendue dans le fichier brut ;
- `modalites_codes` : codes documentés ;
- `codes_speciaux` : non-réponse ou sans objet ;
- `univers` : population à laquelle la question s'applique ;
- `role` : variable d'analyse, de plan, identifiant, etc.
Cette dernière information, **l'univers**, est essentielle. Une absence de réponse à une question sur le télétravail n'a pas le même sens chez une personne en emploi et chez une personne retraitée.
## Trois niveaux de « type »
### Type conceptuel
Il correspond à la nature statistique ou substantive de la variable :
- nominale ;
- ordinale ;
- quantitative discrète ;
- quantitative continue ;
- identifiant ;
- poids ;
- date ;
- question à réponses multiples.
### Type de stockage
Le fichier peut stocker une variable comme :
- nombre entier ;
- nombre décimal ;
- texte ;
- date ;
- valeur + labels.
### Classe R
Après import, R peut afficher :
```text
numeric
character
factor
Date
haven_labelled
haven_labelled_spss
```
Ces niveaux doivent être mis en correspondance, mais ils ne sont pas identiques.
### Exemple : `sante`
La question va de « très bonne » à « très mauvaise ». Conceptuellement, elle est **ordinale**. Dans le CSV, elle est stockée par des nombres. Dans un fichier Stata, elle peut être un vecteur numérique avec labels. Pour l'analyse, on peut décider de la convertir en facteur ordonné.
### Exemple : `id`
`id` est numérique dans le fichier, mais conceptuellement c'est un **identifiant**. Une moyenne de `id` n'a aucune signification.
### Exemple : `poids_final`
`poids_final` est numérique et doit rester numérique, mais il n'est pas une variable substantive : il intervient dans le plan d'analyse.
::: {.callout-warning title="Erreur fréquente — confondre code et mesure"}
Le fait qu'une variable soit stockée sous forme numérique autorise certaines fonctions R, mais ne les rend pas scientifiquement pertinentes. La documentation précède le choix de la statistique.
:::
## Les objets `haven_labelled`
Lorsque `{haven}` importe un fichier Stata, SPSS ou SAS, les valeurs étiquetées sont souvent représentées par un vecteur `haven_labelled` [@haven2026].
```{r}
enquete_dta <- haven::read_dta("data/raw/enqueter_brut.dta")
class(enquete_dta$diplome)
```
Un objet étiqueté conserve :
- ses valeurs numériques ;
- un attribut contenant les labels des valeurs ;
- éventuellement un label de variable.
### Inspecter les labels
Avec `{labelled}` [@labelled2026] :
```{r}
labelled::var_label(enquete_dta$diplome)
labelled::val_labels(enquete_dta$diplome)
```
Pour obtenir une vue plus large :
```{r}
labelled::look_for(enquete_dta, "dipl")
```
`look_for()` est particulièrement utile dans les enquêtes comportant des centaines de colonnes : on peut rechercher un mot dans les noms et labels.
## Pourquoi ne pas convertir toutes les variables immédiatement ?
Une stratégie tentante est :
```r
enquete_dta |>
mutate(across(where(haven::is.labelled), haven::as_factor))
```
Cette conversion peut être pratique pour une table exploratoire, mais l'appliquer automatiquement à toutes les colonnes peut masquer des distinctions importantes :
- un code `98 = ne sait pas` devient une modalité ordinaire ;
- un score numérique étiqueté peut être transformé en facteur alors qu'il doit rester numérique ;
- l'ordre substantiel d'une variable ordinale n'est pas nécessairement correctement défini ;
- une catégorie de référence pour une régression peut être choisie sans réflexion ;
- les valeurs brutes deviennent moins faciles à auditer.
Dans ce livre, nous conservons une **copie brute** et créons des variables d'analyse explicitement.
::: {.callout-tip title="Bon réflexe"}
Avant toute conversion globale, inspecter : le label, les codes, l'univers de la question et l'usage analytique prévu.
:::
## Convertir sélectivement en facteur
Pour une variable catégorielle dont les codes spéciaux ont déjà été traités :
```{r}
diplome_facteur <- haven::as_factor(
enquete_dta$diplome,
levels = "labels"
)
```
Avec `{labelled}`, `to_factor()` fournit aussi des outils de conversion adaptés aux données étiquetées [@labelled2026].
Mais l'étape méthodologique importante reste : **quelles modalités doit-on conserver et dans quel ordre ?**
## Variables nominales et ordinales
### Nominale
Les modalités n'ont pas d'ordre naturel unique.
Exemples :
- territoire ;
- mode de collecte ;
- situation familiale ;
- sexe/genre lorsqu'il est utilisé comme variable nominale.
### Ordinale
Les modalités possèdent un ordre substantiel, sans supposer que l'écart entre deux catégories successives est constant.
Exemples :
- état de santé de « très bon » à « très mauvais » ;
- fréquence d'usage d'Internet ;
- confiance de « aucune » à « très forte ».
Dans R :
```{r}
sante_demo <- factor(
c("Bonne", "Moyenne", "Très bonne", "Mauvaise"),
levels = c("Très mauvaise", "Mauvaise", "Moyenne", "Bonne", "Très bonne"),
ordered = TRUE
)
sante_demo
```
L'ordre doit être écrit explicitement lorsque le tri alphabétique ne correspond pas au sens de la variable.
## Variables quantitatives discrètes et continues
### Discrète
Un compte prend généralement des valeurs entières :
- nombre d'enfants ;
- nombre de livres lus ;
- nombre de sources d'information utilisées.
### Continue
Une mesure peut théoriquement prendre de nombreuses valeurs dans un intervalle :
- revenu ;
- durée ;
- poids physique ;
- température.
Dans la pratique, une variable continue peut être arrondie ou enregistrée en entiers. Là encore, **le stockage ne définit pas seul le concept**.
## Les codes spéciaux
Les enquêtes utilisent souvent des codes placés en dehors de la plage des réponses normales.
Dans notre jeu :
- `97` : souvent « sans objet » pour les questions liées au travail ;
- `98` : « ne sait pas » ;
- `99` : « refus » ;
- `99997`, `99998` : codes spéciaux du revenu afin de ne pas entrer en collision avec des revenus plausibles.
### Pourquoi distinguer « sans objet » de « refus » ?
Prenons `heures_travail` :
- une personne retraitée n'a pas à répondre à la question : **absence structurelle / sans objet** ;
- une personne en emploi qui refuse de donner son nombre d'heures présente une **non-réponse à une question applicable**.
Transformer immédiatement les deux situations en un même `NA` peut être acceptable pour certains calculs, mais seulement après avoir conservé ou documenté la raison de l'absence.
Le chapitre 7 développera ce point.
## L'univers d'une question
Le dictionnaire indique pour `heures_travail` et `teletravail_jours` un univers lié à l'emploi. Cela permet un contrôle logique :
```r
# Pseudo-code conceptuel
si statut_emploi != "en emploi" :
heures_travail devrait être "sans objet"
```
Un fichier peut donc être techniquement valide tout en contenant une incohérence de questionnaire. La documentation permet de formuler les règles de validation du chapitre 6.
## Produire un inventaire des variables
Sur un CSV, on peut créer un inventaire minimal :
```{r}
enquete_csv <- readr::read_csv(
"data/raw/enqueter_brut.csv",
show_col_types = FALSE
)
inventaire <- tibble::tibble(
variable = names(enquete_csv),
classe_r = vapply(enquete_csv, function(x) class(x)[1], character(1)),
n_distinct = vapply(enquete_csv, dplyr::n_distinct, integer(1)),
n_manquant = vapply(enquete_csv, function(x) sum(is.na(x)), integer(1))
)
inventaire
```
Attention : dans le fichier brut, les codes `98` et `99` **ne sont pas encore des `NA`**. Le nombre de valeurs manquantes R ne mesure donc pas toute la non-réponse d'enquête.
### Joindre l'inventaire au dictionnaire
```{r}
dictionnaire <- readr::read_csv(
"data/documentation/dictionnaire_variables.csv",
show_col_types = FALSE
)
inventaire_documente <- inventaire |>
dplyr::left_join(
dplyr::select(dictionnaire, variable, libelle, type_conceptuel, codes_speciaux),
by = "variable"
)
```
Cette jointure rapproche ce que **R observe** de ce que **la documentation déclare**.
::: {.callout-note title="Une bonne pratique très rentable"}
Pour une enquête inconnue, construire rapidement un tableau « variable / label / classe R / nombre de modalités / codes spéciaux » donne souvent une compréhension plus fiable que de parcourir directement des centaines de colonnes dans un tableur.
:::
## Vérifier la correspondance dictionnaire–fichier
Les variables documentées existent-elles toutes dans le fichier ?
```{r}
setdiff(dictionnaire$variable, names(enquete_csv))
```
Et inversement :
```{r}
setdiff(names(enquete_csv), dictionnaire$variable)
```
Un résultat vide est rassurant. Un écart peut être légitime — variable technique ajoutée, version différente du fichier — mais il doit être expliqué.
## Mini-exercices
### Mini-exercice 1 — Nature versus stockage
Pour chaque variable, indiquez un type conceptuel probable :
- `id = 10045` ;
- `poids_final = 1.37` ;
- `sante = 1, 2, 3, 4, 5` ;
- `nb_enfants = 0, 1, 2, 3...` ;
- `territoire = 1, 2, 3, 4, 5`.
::: {.callout-caution collapse="true" title="Correction"}
`id` est un identifiant ; `poids_final` un poids numérique ; `sante` une variable ordinale ; `nb_enfants` un compte quantitatif discret ; `territoire` une variable nominale malgré son codage numérique.
:::
### Mini-exercice 2 — Codes spéciaux
Pourquoi ne faut-il pas calculer directement :
```r
mean(enquete$revenu_mensuel)
```
si `99997 = ne sait pas` et `99998 = refus` ?
::: {.callout-caution collapse="true" title="Correction"}
Ces codes sont de très grands nombres qui ne représentent pas des revenus. Ils gonfleraient artificiellement la moyenne. Il faut d'abord les identifier grâce à la documentation puis les traiter explicitement, en conservant si nécessaire la raison de la non-réponse.
:::
## Exercice de synthèse
### Niveau A — Appliquer
À partir de `dictionnaire_variables.csv` :
1. listez les variables dont `section` contient « Opinions » ou « Plan » ;
2. affichez `variable`, `libelle`, `type_conceptuel` et `codes_speciaux` ;
3. comptez le nombre de variables par `type_conceptuel`.
### Niveau B — Choisir
La variable `satisfaction_vie` est codée de 0 à 10, avec `98` et `99`. Discutez trois représentations possibles dans R : numérique, facteur ordonné, facteur nominal. Laquelle conserveriez-vous pour une analyse moyenne ? laquelle pourrait être pertinente pour un tableau descriptif ?
### Niveau C — Analyser
Construisez un inventaire automatique du fichier brut avec :
- nom de variable ;
- classe R ;
- nombre de valeurs distinctes ;
- nombre de `NA` natifs ;
- label et type conceptuel issus du dictionnaire.
Identifiez ensuite trois variables pour lesquelles la classe R seule serait insuffisante ou trompeuse pour choisir une méthode statistique.
### Correction détaillée
::: {.callout-caution collapse="true" title="Correction — Niveau A"}
```r
dictionnaire |>
filter(grepl("Opinions|Plan", section)) |>
select(variable, libelle, type_conceptuel, codes_speciaux)
dictionnaire |>
count(type_conceptuel, sort = TRUE)
```
L'objectif est de manipuler la documentation comme un jeu de données, plutôt que de la traiter comme une annexe rarement consultée.
:::
::: {.callout-caution collapse="true" title="Éléments de correction — Niveau B"}
Pour une moyenne, la représentation numérique 0–10 conserve l'échelle et permet de calculer directement des statistiques après traitement des codes spéciaux. Un facteur ordonné peut être utile si l'on veut insister sur les catégories ordonnées ou ajuster un modèle ordinal. Un facteur nominal perd l'ordre et serait généralement moins pertinent ici. Aucun choix ne doit faire oublier que l'interprétation d'un écart de 1 point sur une échelle de satisfaction mérite elle aussi une réflexion substantive.
:::
## À retenir
- Les données d'enquête doivent être lues avec leur questionnaire et leur dictionnaire.
- Nom, label, code et label de valeur sont des objets distincts.
- Il faut distinguer type conceptuel, type de stockage et classe R.
- `haven_labelled` conserve des métadonnées utiles ; il ne doit pas être converti aveuglément [@haven2026].
- `{labelled}` permet d'inspecter labels et dictionnaires de variables [@labelled2026].
- Les codes spéciaux doivent être identifiés avant les calculs.
- « Sans objet » n'est pas synonyme de « refus ».
- L'univers d'une question permet de tester la cohérence entre variables.
- Une jointure entre inventaire technique et dictionnaire est un excellent point de départ d'audit.
## Pour aller plus loin
La documentation de `{haven}` détaille la représentation des données étiquetées importées depuis les logiciels statistiques [@haven2026]. Le package `{labelled}` fournit des fonctions destinées à la manipulation et à la documentation de ces données [@labelled2026].
Nous disposons maintenant de deux sources d'information : **le fichier brut** et **sa documentation**. Le chapitre suivant va les confronter pour repérer doublons, valeurs impossibles et incohérences avant de modifier quoi que ce soit.