From f7bf28c1f5604787d39527120ed971d242e49af3 Mon Sep 17 00:00:00 2001 From: Anne Husseini-Skalitz <71011059+AnneHuSKa@users.noreply.github.com> Date: Fri, 31 May 2024 16:18:21 +0200 Subject: [PATCH] Add files via upload --- .../indicatrice-boucle.md | 31 +++++ .../pogues/Quelques cas pratiques/kish.md | 85 ++++++++++++ .../Quelques cas pratiques/libelles-flous.md | 88 ++++++++++++ .../migration-xpath-vers-vtl.md | 131 ++++++++++++++++++ 4 files changed, 335 insertions(+) create mode 100644 bowiedocs/docs/pogues/Quelques cas pratiques/indicatrice-boucle.md create mode 100644 bowiedocs/docs/pogues/Quelques cas pratiques/kish.md create mode 100644 bowiedocs/docs/pogues/Quelques cas pratiques/libelles-flous.md create mode 100644 bowiedocs/docs/pogues/Quelques cas pratiques/migration-xpath-vers-vtl.md diff --git a/bowiedocs/docs/pogues/Quelques cas pratiques/indicatrice-boucle.md b/bowiedocs/docs/pogues/Quelques cas pratiques/indicatrice-boucle.md new file mode 100644 index 00000000..3d59c5d3 --- /dev/null +++ b/bowiedocs/docs/pogues/Quelques cas pratiques/indicatrice-boucle.md @@ -0,0 +1,31 @@ +# Utilisation d'une indicatrice dans une boucle + +Dans ce scénario, on collecte dans __une boucle__ des informations sur l'occupation de résidences secondaires à travers une liste de statuts (propriétaire, locataire, etc.) - la collecte se faisant sur la variable `OCCUPATION`. + +On veut précisément savoir s'il y a au moins une réponse de type "locataire" pour afficher après la boucle une question à ce sujet. + +Pour cette mise en place, nous allons : + +- créer une variable calculée de __portée boucle__ que nous appelons `OCCUPATION_LOCATION` +- créer une variable calculée de __portée questionnaire__ que nous appelons `SOMME_LOCATION` +- créer un filtre qui s'appuie sur cette dernière variable. + +La variable `OCCUPATION_LOCATION` est une indicatrice qui s'active si le choix se porte sur le statut "locataire" - dans ce cas la variable `OCCUPATION` prendra la valeur `"2"`. Le code VTL sera donc : + +```vtl +if $OCCUPATION$ = "2" then 1 else 0 +``` + +On comprend donc que pour chaque réponse de type "locataire" on va créer une variable de boucle `OCCUPATION_LOCATION` qui vaudra `1`. + +La variable `SOMME_LOCATION` va agréger ces résultats avec : + +```vtl +sum($OCCUPATION_LOCATION$) +``` + +Si au moins une réponse de type "locataire" a été faite alors `SOMME_LOCATION` sera strictement positive. Le filtre aura donc comme code VTL : + +```vtl +SOMME_LOCATION > 1 +``` diff --git a/bowiedocs/docs/pogues/Quelques cas pratiques/kish.md b/bowiedocs/docs/pogues/Quelques cas pratiques/kish.md new file mode 100644 index 00000000..0c3ca118 --- /dev/null +++ b/bowiedocs/docs/pogues/Quelques cas pratiques/kish.md @@ -0,0 +1,85 @@ +# Sélection du Kish + +Ce document décrit une méthode pour sélectionner le Kish dans Pogues. + +!!! tip "Mise à jour du 19/01/2024" + + Une nouvelle version de ce guide de sélection d'individu qui inclut un aléa basé sur le prénom du répondant afin de distinguer les personnes nées les mêmes jour et mois. + +## Principe + +On considère que l'on procède à l'identification du Kish à travers les étapes suivantes : + +- on demande le nombre d'habitants du ménage +- on boucle sur ce nombre pour collecter les prénoms et les dates de naissance de chacun des membres du ménage +- une dernière boucle va permettre de filtrer le questionnement sur le seul Kish + +## Structure du questionnaire + +### Séquence d'identification + +> On construit une séquence contenant les questions permettant d'identifier le Kish contenant la question du nombre d'habitants et la sous-séquence d'identification. + +On crée une séquence contenant une première question pour collecter le nombre d'habitants (variable numérique collectée `NBHAB`). + +On crée ensuite dans cette même séquence une sous-séquence `IDENTIFICATION` contenant : + +- une question pour collecter le prénom de chaque habitant (variable texte collectée `PRENOM`). +- une question pour collecter la date de naissance (variable date `DATE_DE_NAISANCE`) + +Il faut ensuite créer une boucle `BOUCLE_PRENOMS` sur cette sous-séquence avec la formule `cast($NBHAB$, integer)` pour le minimum et le maximum. + +### Séquence de questions + +> On crée la séquence de questionnement + +Une séquence contenant une question `QUESTION_POUR_LE_KISH`, dont le libellé est personnalisé avec le prénom (via la formule VTL `"Question pour " || cast($PRENOM$, string)`). + +On crée la boucle `BOUCLE_QUESTION_KISH` basée sur `BOUCLE_PRENOMS` qui englobe la séquence de questions pour le Kish. + +## Calcul du Kish + +> Les éléments permettant de procéder au calcul lui-même + +Le coeur de la sélection est la formule permettant de former un score de sélection : + +`cast(if $MOIS_NAISSANCE_INT$ < 6 then $MOIS_NAISSANCE_INT$ + 12 else $MOIS_NAISSANCE_INT$, string) || "." || $JOUR_NAISSANCE_STR$` + +Elle donnera par exemple : + +- pour la date de naissance `01/06/2000` le score `6.01` +- pour `10/05/1990` le score `17.10` + +:octicons-report-16: On ajoute à ce premier score un aléa tiré à partir de la position de certaines lettres dans le prénom, voir les formules ci-dessous des variables `ALEA_PRENOM` et `SCORE_KISH_INT_ALEA_PRENOM`. Cela permet de traiter le cas de personnes nées les mêmes jour et mois. + +!!!note + + La formule donnée plus bas pour la création de l'aléa peut être adaptée, amendée pour améliorer la production d'un aléa. Cependant, il faut veiller à rester parcimonieux pour ne pas créer un code difficile à maintenir. + + Par ailleurs, on introduira dans le courant du S1 2024 une fonction VTL pour générer de l'aléa, elle pourra remplacer une formule complexe dans ce contexte. + +On sélectionne ensuite l'individu dont le score est le plus bas. + +Les variables calculées nécessaires sont : + +| Variable | Portée | VTL | +|--------------------|----------------|------------------------------------------------------------------------------------| +| MOIS_NAISSANCE_INT | BOUCLE_PRENOMS | `cast(cast(cast($DATE_DE_NAISSANCE$, date, "YYYY-MM-DD"), string, "MM"), integer)` | +| JOUR_NAISSANCE_STR | BOUCLE_PRENOMS | `cast(cast($DATE_DE_NAISSANCE$, date, "YYYY-MM-DD"),string, "DD")` | +| SCORE_KISH | BOUCLE_PRENOMS | `cast(if $MOIS_NAISSANCE_INT$ < 6 then $MOIS_NAISSANCE_INT$ + 12 else $MOIS_NAISSANCE_INT$, string) || "." || $JOUR_NAISSANCE_STR$` | +| SCORE_KISH_INT | BOUCLE_PRENOMS | `cast($SCORE_KISH$, number)` | +| ALEA_PRENOM | BOUCLE_PRENOMS | `instr(lower(PRENOM), "e") + instr(lower(PRENOM), "a") + instr(lower(PRENOM), "i") + instr(lower(PRENOM), "s") + instr(lower(PRENOM), "n") + instr(lower(PRENOM), "r") + instr(lower(PRENOM), "t") + instr(lower(PRENOM), "o")` | +| SCORE_KISH_INT_ALEA_PRENOM | BOUCLE_PRENOMS | `$SCORE_KISH_INT$ + $ALEA_PRENOM$ / 100` | +| KISH_MIN | Questionnaire | `min($SCORE_KISH_INT_ALEA_PRENOM$)` | +| KISH_INDICATOR | BOUCLE_PRENOMS | `if $KISH_MIN$ = $SCORE_KISH_INT_ALEA_PRENOM$ then 1 else 0` | +| NB_POTENTIAL_KISH | Questionnaire | `sum($KISH_INDICATOR$)` | + +## Filtre + +Pour ne présenter qu'un seul jeu de questions à l'individu sélectionné, il est nécessaire d'ajouter un filtre sur ces questions à partir du score calculé en amont. + +Le filtre a pour formule `$KISH_INDICATOR$ = 1`. + +## Questionnaire exemple + +Pour référence, [un questionnaire implémentant cette solution](https://pogues.demo.insee.io/questionnaire/l8lfytfu). diff --git a/bowiedocs/docs/pogues/Quelques cas pratiques/libelles-flous.md b/bowiedocs/docs/pogues/Quelques cas pratiques/libelles-flous.md new file mode 100644 index 00000000..144884b2 --- /dev/null +++ b/bowiedocs/docs/pogues/Quelques cas pratiques/libelles-flous.md @@ -0,0 +1,88 @@ +# Collecte par libellés flous + +Lors de la collecte de la profession d'un enquêté, la première réponse se fait traditionnellement à travers une liste fournie de dénominations (et par le truchement d'une recherche sur liste avec autocomplétion). Il peut cependant arriver que le répondant ne trouve pas de libellés qui le satisfasse. Dans ce cas on lui proposera en deuxième intention un champ de réponse libre. Dans ce cas de figure on peut chercher à identifier ce que l'on appelle des _libellés flous_ c'est-à-dire pour lesquels on va demander de préciser la réponse. + +Le schéma de questionnement est donc le suivant : + +```vtl +- La question initiale (liste simple ou suggester) +- La question avec réponse sur champ libre + - Filtrée sur la non réponse à la question initiale + - Normalisation du libellé en clair +- L'identification d'un libellé flou +- La question de précision + - Filtrée sur l'appartenance du libellé en clair à la liste des libellés flous +``` + +## Mode opératoire + +On commence donc par créer la question initiale, avec un type de réponse à choix unique ou via une recherche sur liste (:warning: pas encore directement implémenté dans Pogues). La variable issue de cette réponse sera nommée `PROFESSION`. + +Pour pouvoir proposer une deuxième question proposant un champ texte libre et une variable de collecte `PROFESSION_EN_CLAIR`. Cette question sera filtrée par l'expression : + +`isnull($PROFESSION$)` + +Avant de pouvoir mobiliser cette réponse, nous allons la normaliser pour coller à la liste existante des libellés flous. Cette normalisation : + +- transforme les caractères en minuscules +- supprime les espaces (`" "`) +- remplace des caractères accentués en caractères non accentués (par exemple un `à` en `a`) +- enfin passe en majuscules le libellé obtenu par ces transformations + +Le code VTL sera : + +```vtl +upper( + replace( + replace( + replace( + replace( + replace( + replace(lower($PROFESSION_EN_CLAIR$), " ", "") + , "à", "a") + , "ç", "c") + , "é", "e") + , "è", "e") + , "ê", "e") + ) +``` + +> Vous trouverez plus bas, une explication détaillé du code. + +On crée ensuite une troisième question demandant des précisions sur le libellé entré en clair si celui-ci est dans la liste des libellés flous. Pour cela, on crée un filtre sur cette troisième question qui s'appuie sur la variable `PROFESSION_EN_CLAIR_DANS_LIBELLES_FLOUS` dont le code sera : + +```vtl +$PROFESSION_EN_CLAIR$ in {"ACCOMPAGNATEUR", +"ACCOMPAGNATRICE", +"ACHETEUR", +"ACHETEUSE", +"ACTIVITESAISONNIERE", +"ADJOINT", +"ADJOINTADMINISTRATIF", +"ADJOINTADMINISTRATIFPRINCIPAL", +"ADJOINTADMINISTRATIFTERRITORIAL", +"ADJOINTTECHNIQUE", +"ADJOINTTECHNIQUEALACOMMUNE", +[...] +} +``` + +La liste même des libellés est à obtenir par ailleurs. + +## Détail du code de transformation du libellé en clair + +- `lower($PROFESSION_EN_CLAIR$)` : `PROFESSION_EN_CLAIR` est entièrement mis en minuscule +–> ex: “IntérmittÊnt du spèctàçle” devient “intérmittênt du spèctàçle” + +- `replace([...], " ", "")` : On retire tous les espaces du libellé en minuscule (y.c. ceux “légitimes” entre les mots) +–> ex: “intérmittênt du spèctàçle” devient “intérmittêntduspèctàçle” + +- `replace([...], "à", "a")` : On remplace - dans le libellé en minuscule, sans espace - tous les à en a, tous les ç en c, tous les éèê en e. +–> ex: “intérmittêntduspèctàçle” devient “intérmittêntduspèctaçle” +puis “intérmittêntduspèctacle” +puis “intermittêntduspèctacle” +puis “intermittêntduspectacle” +puis “intermittentduspectacle” + +- `upper([...])` : Le libellé normalisé en minuscule est repassé entièrement en majuscules +–> ex: “intermittentduspectacle” devient “INTERMITTENTDUSPECTACLE” diff --git a/bowiedocs/docs/pogues/Quelques cas pratiques/migration-xpath-vers-vtl.md b/bowiedocs/docs/pogues/Quelques cas pratiques/migration-xpath-vers-vtl.md new file mode 100644 index 00000000..525f37be --- /dev/null +++ b/bowiedocs/docs/pogues/Quelques cas pratiques/migration-xpath-vers-vtl.md @@ -0,0 +1,131 @@ +# XPath et VTL, les différences + +Ce document est un résumé permettant de traduire rapidement quelques fonctions ou syntaxes fréquemment utilisées dans les questionnaires entreprises saisis dans Pogues. + +!!! note + + Pour (re)découvrir de façon plus approfondie et détaillée le langage VTL, [le guide VTL de référence est ici](vtl.md). + +## Changements au niveau du langage + +### Quelques opérateurs identiques + +| Opérateur ou fonction | Xpath | VTL | +| --- | ----- | -------- | +| A est égal à B | A = B | A = B| +| A plus B| A + B | A + B| +| A moins B| A - B | A - B| +| A fois B| A * B | A * B| +| et logique | and | and | +| ou logique | or | or | + +### Quelques opérateurs différents + +| Opérateur ou fonction | Xpath | VTL | +| --- | ----- | -------- | +| A différent de B | A != B | A <> B| +| A divisé par B| A div B | A / B| +| sous-chaine de longueur 2, à partir du 1er caractère | substring(A,1,2) | substr(A,1,2)| +| concaténer A, B | concat(A,B ) | A \|\| B | +| nullité (cf. infra) | A = '' | isnull(A)| + +### Utilisation de texte + +Dans les contrôles ou les filtres décrits dans Pogues, on n'utilise plus (comme c'était le cas en Xpath) les simples `'` mais des guillemets `"`. + +__Exemples__ : + +- Filtre : `$VAR_TEXTE$ = "1" or $VAR_TEXTE$ ="2"` +- Contrôle : `$VAR_TEXTE$ = "1" and $VAR_NUMERIQUE$ > 1000` + +## Changements dûs au format des variables (passage XForms -> Lunatic) + +Le format des variables a évolué ce qui conduit à quelques évolutions dans la manière de formuler filtres ou contrôles. + +### Nature des modalités de réponse aux QCM + +En VTL, on ne retourne plus des "0" / "1" ou des "" / "1" pour les modalités de réponse à un QCM, mais __true__ si une modalité est cochée, __null__ ou __false__ si elle ne l'est pas. Cf. partie "les contrôles dans les QCM". + +### Comprendre et gérer le vide et la nullité + +#### Généralités + +En xforms, la non-réponse était systématiquement une chaîne vide quel que soit le format. +Dans le format Lunatic en revanche, un champ qui n’est pas encore rempli par le répondant est de valeur __"null"__, que ce soit un champ nombre, texte, un QCU, un QCM etc. +Quand le répondant saisit une réponse, on va collecter un nombre, du texte, un booléen (valeurs true/false, cf. supra). +:warning: Lorsque le répondant saisit une réponse puis l'efface, le champ collecté n'est pas systématiquement remis à __null__ : il redeviendra __null__ pour un champ nombre mais vaudra "" pour du texte, et false pour une modalité de QCM décochée. + +| Champ collecté | jamais saisi | répondu / coché | effacé/décoché | +| -------- | -------- | -------- | -------- | +| Nombre | null | 123 | null | +| Texte | null | "xyz" | "" | +| Modalité de QCM | null | true | false | +| Modalité de QCU | null | un code (décrit dans Pogues) | impossible | + +#### Sommer des variables + +Quand on manipule des variables numériques en VTL, il faut se prémunir de ce null ou ce "" puisqu'en VTL, la valorisation de VAR1_NUMERIQUE + VAR2_NUMERIQUE, si VAR2_NUMERIQUE est non rempli, vaudra null (alors qu'on pourrait s'attendre à ce que la somme soit VAR1_NUMERIQUE). +Pour cela, on utilise la fonction __nvl__ qui permet de proposer une valeur en cas de null ou de "" : nvl(\$MA_VARIABLE$, "valeur si nulle") c'est-à-dire : si \$MA_VARIABLE$ n'est pas renseignée, lui affecter la valeur si nulle, sinon lui affecter \$MA_VARIABLE$. + +__Exemple__: + +- `$VAR1_NUMERIQUE$ + $VAR2_NUMERIQUE$` => `nvl($VAR1_NUMERIQUE$,0) + nvl($VAR2_NUMERIQUE$,0)` + +#### Tester la nullité/le vide + +On peut vouloir détecter des potentielles non-réponses (par exemple pour ne pas déclencher un contrôle entre 2 variables VAR_A et VAR_B, si une des 2 variables n'est pas renseignée). Pour cela, on va devoir tester la nullité des variables et, en fonction de la nature de la variable collectée, s'assurer que l'on n'a pas aussi une chaîne vide. +Plusieurs syntaxes sont possibles : + +- `isnull($VAR_NUMERIQUE$) (pour les variables numériques)` +- `isnull($VAR_TEXTE$) or $VAR_TEXTE$="" (pour les textes).` +- `isnull($VAR_QCM1$) or not $VAR_QCM1$ (pour les modalités de QCM).` +- `isnull($VAR_QCU$) (pour un QCU)` + +On peut également tirer partie de la fonction __nvl__ : + +- `nvl($VAR_TEXTE$, "") = ""` +- `nvl($VAR_QCM_1$, false)` + +### Personnaliser un libellé + +Trois éléments assez différents de Xpath : + +- on utilise l’opérateur VTL __\||__ qui permet de concaténer des chaînes de caractères, ou une chaîne de caractères et une variable. +- pour être utilisées dans un libellé, les variables numériques collectées doivent être converties en chaînes de caractères (fonction __cast__) +- les variables externes, _quelle que soit leur nature_, sont vues comme des variables Texte, qui peuvent donc être utilisées dans des libellés (de questions, de déclarations, de messages d'erreur) + +__Exemples__ : + +- `"Hello" || $VAR_TEXTE$` +- `"En " || $VAR_TEXTE_EXTERNE$ || ", votre activité est-elle toujours " || $VAR_TEXTE_EXTERNE2$ || " ?"` +- `"Votre chiffre d'affaires est de " || cast($VAR1_NUMERIQUE$,string) || " euros et votre effectif de " || cast($VAR2_NUMERIQUE$,string) || " personnes".` +- `"Vous venez de déclarer un chiffre d'affaires de " || cast($VAR1_NUMERIQUE$,string) || " euros alors qu'il était de " || cast($VAR2_NUMERIQUE_EXTERNE$,string) || " euros l'an dernier".` +ou + `"Vous venez de déclarer un chiffre d'affaires de " || cast($VAR1_NUMERIQUE$,string) || " euros alors qu'il était de " || $VAR2_NUMERIQUE_EXTERNE$ || " euros l'an dernier".` + +### Contrôles et variables calculées + +Il est assez simple d'écrire des contrôles ou de calculer des variables à partir des données collectées ou externes dès lors qu'on dispose des opérateurs (cf. infra), qu'on a compris le principe de la nullité et qu'on connaît la nature des variables, en particulier celles des variables externes. + +__Exemples__ : + +- `sans gestion du null : if $VAR_NUMERIQUE$ < 10 then "1" else "2" ==> renvoie 2 si null` +- `gestion du null : if nvl($VAR_NUMERIQUE$,0) < 10 then "1" else "0" ==> renvoie 1 si null` +- `variable externe (on doit convertir la variable en numérique pour la comparer à 0 par exemple): if nvl($VAR2_NUMERIQUE_EXTERNE, "") <> 0 and cast($VAR2_NUMERIQUE_EXTERNE$,integer) > 0 then "1" else "0"` +- `$VAR_SOMME$ = nvl($VAR1_NUMERIQUE,0) + nvl($VAR2_NUMERIQUE$,0)` + +### Contrôles dans les QCM + +Dans la nouvelle filière, on ne retourne plus des 0 / 1 pour les modalités de réponse à un QCM, mais des true si une modalité est cochée, null si elle ne l'est pas et false si elle est décochée. +Les contrôles ou filtres impliquant ces variables doivent prendre en compte ces aspects. + +__Exemples__ : + +- tester que QCM1 est cochée (pour un filtre par exemple) => `nvl($QCM1$,false) = true` +- tester une modalité exclusive (ici par exemple QCM4 ne peut pas être cochée si QCM1, QCM2, ou QCM3 l'est) => `(nvl($QCM4$,false) = true and nvl($QCM3$,false) = true) or (nvl($QCM4$,false) = true and nvl($QCM2$,false) = true) or (nvl($QCM4$,false) = true and nvl($QCM1$,false) = true))` + +## Et si le questionnaire ne peut pas être visualisé ou se visualise mal ? + +- Si la visualisation du questionnaire ne fonctionne pas, il est possible de visualiser chaque séquence/sous-séquence l'une après l'autre, afin de déterminer quelle séquence/sous-séquence pose un problème, puis quelle question. +- Si une question filtrée s'affiche à tort, c'est que le filtre est incorrect (variable mal décrite, inexistante) +- Si es déclarations n’apparaissent pas, penser à vérifier que le(s) mode(s) de collecte est(sont) bien coché(s).