cassionAnalyse de données

Retour à la leçonLeçon 4 sur 8Des données qui gardent leur sens

Les facteurs, et l'ordre qu'exige un rapport

Le même diaporama que les téléchargements, rendu sous forme de page. Lancez le diaporama pour le présenter en plein écran — les flèches ou un clic avancent d'une diapositive, Échap quitte.

Diapositives · PDFDiapositives · PowerPoint

  1. Diapositive 1 / 20

    Ce que couvre cette leçon

    • Un facteur est un entier assorti d'une table de correspondance
    • Le piège de as.numeric()
    • Fixer l'ordre voulu
    • Les facteurs ordonnés
    • Les niveaux inutilisés, et les deux comportements qui divergent
    • Réduire une longue traîne
    • Facteurs et valeurs manquantes
    • Là où les facteurs mordent dans une jointure
    • Ce qui vient ensuite
    Notes du présentateur
    Ce qu'est réellement un facteur, le piège de as.numeric() qui renvoie silencieusement des positions de niveaux, et les verbes forcats qui mettent une échelle JMP dans l'ordre de l'échelle plutôt que dans celui de l'alphabet.
  2. Diapositive 2 / 20

    Un facteur est un entier assorti d'une table de correspondance — En R

    service <- factor(c("basic", "limited", "unimproved", "basic"))
    
    levels(service)
    #> [1] "basic"      "limited"    "unimproved"
    
    as.integer(service)
    #> [1] 1 2 3 1
    Notes du présentateur
    En dessous, R stocke 1 2 3 1 et un vecteur de caractères contenant les niveaux. Tout ce qui suit — le problème d'ordre, le piège de as.numeric(), les niveaux inutilisés — découle de ce seul fait. Remarquez que les niveaux sont alphabétiques. Rien dans basic, limited, unimproved n'indique que ce soit l'ordre, et c'est exactement l'inverse pour une échelle de service du JMP, où non améliorée est le pire et où le service de base vaut mieux que le service limité. Laissé tel quel, chaque tableau et chaque graphique bâti sur cette colonne se lit dans un ordre qui ne signifie rien.
  3. Diapositive 3 / 20

    Le piège de as.numeric() — En R

    age <- factor(c("10", "9", "8"))
    
    as.numeric(age)
    #> [1] 1 3 2
    Notes du présentateur
    C'est l'erreur de facteur la plus coûteuse, et elle n'avertit pas.
  4. Diapositive 4 / 20

    Le piège de as.numeric() — En R

    as.numeric(as.character(age))
    #> [1] 10 9 8
    Notes du présentateur
    Ce sont des positions de niveaux, non des valeurs. Les niveaux sont alphabétiques — "10", "8", "9" — donc "10" est en position 1 et "9" en position 3. as.character() d'abord, systématiquement. Le cas survient dès qu'une colonne numérique a été lue comme du texte — une colonne Excel avec un "n/a" égaré, un CSV lu en col_character() — puis convertie en facteur en chemin. Méfiez-vous d'une moyenne suspectement proche du nombre de catégories.
  5. Diapositive 5 / 20

    Fixer l'ordre voulu — En R

    library(forcats)
    
    ladder <- fct_relevel(service, "unimproved", "limited", "basic")
    levels(ladder)
    #> [1] "unimproved" "limited"    "basic"
  6. Diapositive 6 / 20

    Fixer l'ordre voulu — En R

    fct_infreq(source)        # le niveau le plus frequent en premier
    fct_reorder(name, value)  # ordonner un facteur par une autre colonne
    Notes du présentateur
    fct_relevel() nomme l'ordre explicitement. Déclarez-le une fois, près de l'endroit où la colonne est créée, et chaque tableau, graphique et modèle en aval en hérite. Deux verbes forcats gagnent immédiatement leur place :
  7. Diapositive 7 / 20

    Fixer l'ordre voulu — En R

    library(dplyr)
    
    by_commune |>
      mutate(commune = fct_reorder(commune, gam_rate)) |>
      ggplot2::ggplot(ggplot2::aes(gam_rate, commune)) +
      ggplot2::geom_col()
    Notes du présentateur
    fct_reorder() est ce qui transforme un graphique en barres illisible en graphique lisible — les communes triées par leur taux de MAG plutôt que par l'alphabet — et il le fait sans un levels = manuel à mettre à jour quand les données changent.
  8. Diapositive 8 / 20

    Les facteurs ordonnés — En R

    service[1] >= service[2]
    #> Warning: '>=' not meaningful for factors
    #> [1] NA
    Notes du présentateur
    fct_relevel() fixe l'ordre des niveaux. Il ne rend pas le facteur comparable :
  9. Diapositive 9 / 20

    Les facteurs ordonnés — En R

    ladder <- factor(
      c("basic", "limited"),
      levels = c("unimproved", "limited", "basic"),
      ordered = TRUE
    )
    
    ladder[1] >= ladder[2]
    #> [1] TRUE
    Notes du présentateur
    Pour une échelle, où « au moins de base » est une vraie question, déclarez-la ordonnée :
  10. Diapositive 10 / 20

    Les facteurs ordonnés

    • Employez les facteurs ordonnés avec parcimonie — Ils changent la façon dont les modèles traitent la variable…
    Notes du présentateur
    >= "basic" calcule alors directement l'indicateur de couverture du JMP. Sans ordered = TRUE, l'expression renvoie NA avec un avertissement — qui, s'il n'est pas lu, devient un chiffre de couverture à NA ou, pire, un filtre qui ne sélectionne rien. Employez les facteurs ordonnés avec parcimonie. Ils changent la façon dont les modèles traitent la variable (contrastes polynomiaux plutôt qu'indicatrices), ce qui est rarement souhaité dans une régression. Pour une échelle de service, une bande de sévérité ou une phase IPC, l'ordre en vaut la peine. Pour une commune, non.
  11. Diapositive 11 / 20

    Les niveaux inutilisés, et les deux comportements qui divergent — En R

    d <- tibble::tibble(k = factor(c("a", "b", "a"), levels = c("a", "b", "c")))
    
    nrow(dplyr::count(d, k))
    #> [1] 2
    
    length(table(d$k))
    #> [1] 3
    Notes du présentateur
    Un niveau sans ligne reste un niveau. Son apparition dans votre sortie dépend de la fonction interrogée, et R n'est pas cohérent avec lui-même sur ce point.
  12. Diapositive 12 / 20

    Les niveaux inutilisés, et les deux comportements qui divergent — En R

    dplyr::count(d, k, .drop = FALSE)   # conserver le niveau vide
    droplevels(d$k)                     # retirer les niveaux sans ligne
    forcats::fct_drop(d$k)              # la meme chose, en forcats
    Notes du présentateur
    count() écarte le niveau vide ; table() le conserve. Les deux sont justes pour des questions différentes, et la question est celle-là même que le cours Python pour les données de programme soulève à propos d'observed= : rapporter sur les formations ayant transmis des données veut le niveau vide en moins, et rapporter la couverture face à une liste de formations qui auraient dû transmettre le veut présent, car une formation à zéro ligne est justement le constat. Dites lequel vous voulez :
  13. Diapositive 13 / 20

    Réduire une longue traîne — En R

    source <- factor(wash$water_source)
    length(levels(source))
    #> [1] 10
    
    levels(fct_lump_n(source, 4))
    #> [1] "borehole" "piped-into-dwelling" "piped-into-yard" "public-tap" "Other"
    Notes du présentateur
    Dix sources d'eau, c'est trop de lignes pour un tableau de rapport et trop de couleurs pour un graphique.
  14. Diapositive 14 / 20

    Réduire une longue traîne

    • Ne repliez pas avant de calculer un indicateur — Other mêle ici les sources protégées, qui sont améliorées, et l'eau…
    Notes du présentateur
    fct_lump_n() conserve les quatre plus fréquents et replie le reste dans Other. Ne repliez pas avant de calculer un indicateur. Other mêle ici les sources protégées, qui sont améliorées, et l'eau de surface, qui ne l'est pas : un taux de couverture calculé après repli est donc faux. Repliez pour la présentation, sur une copie, une fois les chiffres arrêtés.
  15. Diapositive 15 / 20

    Réduire une longue traîne — En R

    fct_recode(source,
      improved = "borehole",
      improved = "protected-well",
      unimproved = "surface-water"
    )
    Notes du présentateur
    fct_recode() est l'alternative explicite et c'est ce qu'il faut pour une classification : elle nomme chaque correspondance, si bien qu'une source apparaissant au prochain export sans figurer dans la liste reste elle-même au lieu de rejoindre silencieusement un groupe.
  16. Diapositive 16 / 20

    Facteurs et valeurs manquantes — En R

    table(muac$outcome, useNA = "ifany")
    Notes du présentateur
    NA n'est pas un niveau : il survit donc à tout réordonnancement et n'apparaît dans table() que si vous le demandez :
  17. Diapositive 17 / 20

    Facteurs et valeurs manquantes — En R

    muac <- muac |> mutate(outcome = fct_na_value_to_level(outcome, level = "non renseigne"))
    Notes du présentateur
    Pour faire de l'absence une catégorie explicite — ce qui est souvent juste dans un rapport, où « non renseigné » est un constat et non un trou : Une fois devenue un niveau, elle sera comptée, tracée et sommée comme les autres. C'est le but, et c'est aussi le risque : un taux calculé sur un facteur incluant « non renseigné » n'a pas le même dénominateur qu'un taux qui l'exclut.
  18. Diapositive 18 / 20

    Là où les facteurs mordent dans une jointure — En R

    left_join(muac, sites, by = "commune")
    Notes du présentateur
    Si commune est un facteur dans un tableau et du caractère dans l'autre, dplyr convertit et avertit. Si c'est un facteur dans les deux avec des niveaux différents, la jointure fonctionne quand même — dplyr compare les étiquettes, non les entiers — mais les niveaux du résultat sont l'union des deux, ce qui peut discrètement réintroduire des catégories vides. L'habitude la plus simple : joignez sur des colonnes de caractères, convertissez en facteur ensuite. Les facteurs sont un dispositif de présentation et de modélisation, non un type de clé.
  19. Diapositive 19 / 20

    Ce qui vient ensuite

    • Les colonnes portent désormais leur sens et leur ordre.
    Notes du présentateur
    Les colonnes portent désormais leur sens et leur ordre. L'unité suivante les travaille : les verbes dplyr, puis l'appel de regroupement où naissent la plupart des erreurs d'indicateurs.
  20. Diapositive 20 / 20

    La suite

    Lire la leçon complète, avec le code exécutable Retour à la leçon