4  Poser le secret sur plusieurs tableaux liés

Etapes de la pause du secret sur tableaux liés
  1. Analyser les tableaux pour construire une liste de tableaux et une liste de variables de croisement.
  2. Poser le secret primaire sur chacun des tableaux indépendamment.
  3. Calculer le nombre de cellules détectées comme à risque dans chacun des tableaux (i.e. le nombre cellules en secret primaire).
  4. Poser le secret secondaire en utilisant la fonction tab_multi_manager().
  5. Faire une synthèse de la pose du secret dans chaque tableau.

Objectif : savoir protéger un ensemble de tableaux liés en utilisant la fonction tab_multi_manager() du package rtauargus.

Ce chapitre a été réalisé avec la version 1.2.0 de rtauargus et la version 4.2.3 de TauArgus.

library(rtauargus)
library(dplyr)

Appliquons les étapes présentées ci-dessus sur quatre tableaux présents nativement dans le package rtauargus.

data("turnover_act_size")
data("turnover_act_cj")
data("turnover_nuts_size")
data("turnover_nuts_cj")

4.1 Analyser les caractéristiques des tableaux

4.1.1 Détecter liens par les marges

Les tableaux présentés ici ont la structure suivante :

  • turnover_act_size: chiffre d’affaires ventilé par activité et taille de l’entreprise
  • turnover_act_cj: chiffre d’affaires ventilé par activité et taille de l’entreprise
  • turnover_nuts_size: chiffre d’affaires ventilé par nuts et taille de l’entreprise
  • turnover_nuts_cj: chiffre d’affaires ventilé par nuts et catégorie juridique de l’entreprise

Ils sont liés par leurs marges:

  • turnover_act_size et turnover_act_cj partagent les marges d’activité
  • turnover_nuts_size et turnover_nuts_cj partagent les marges des nuts
  • turnover_act_size et turnover_nuts_size partagent les marges de taille
  • turnover_act_cj et turnover_nuts_cj partagent les marges de catégorie juridique

4.1.2 Réperer les variables hiérarchiques

Les variables ACTIVITY et NUTS sont hiérarchiques. Il faut donc constituer les fichiers argus nécessaires.

Les tables de correspondance associées à ces variables sont présents dans le package : activity_corr_table et nuts23_fr_corr_table.

data("activity_corr_table")
data("nuts23_fr_corr_table")

On utilise ces tables de correspondance pour construire les fichiers hiérarchiques pour TauArgus.

act_hrc_file <- write_hrc2(activity_corr_table, 
                           file_name = "tauargus_files/hrc/activity.hrc")

nuts_hrc_file <- write_hrc2(nuts23_fr_corr_table, 
                           file_name = "tauargus_files/hrc/nuts23.hrc")

Cette fonction crée les fichiers hiérarchiques .hrc dans le répertoire indiqué dans l’argument file_name et retourne le chemin de ce document.

act_hrc_file
[1] "tauargus_files/hrc/activity.hrc"
nuts_hrc_file
[1] "tauargus_files/hrc/nuts23.hrc"

4.1.3 Construire une liste de tableaux et une liste de variables de croisement

Dans le code ci-dessous, nous manipulons les objets list de R. Si ce type d’objets ne vous est pas familier, vous pouvez vous reporter à l’annexe 12 qui présente les listes et comment les manipuler.

liste_4tabs <- list(
  act_size = turnover_act_size,
  act_cj = turnover_act_cj,
  nuts_size = turnover_nuts_size,
  nuts_cj = turnover_nuts_cj
)
liste_vars_4tabs <- purrr::map(
  liste_4tabs,
  function(data) colnames(data)[1:2]
)
str(liste_vars_4tabs)
List of 4
 $ act_size : chr [1:2] "ACTIVITY" "SIZE"
 $ act_cj   : chr [1:2] "ACTIVITY" "CJ"
 $ nuts_size: chr [1:2] "NUTS" "SIZE"
 $ nuts_cj  : chr [1:2] "NUTS" "CJ"

Avertissement : il faut repérer les codes servant au total et de s’assurer qu’ils sont cohérents pour une même variable apparaissant dans plusieurs tableaux. En effet, deux tableaux partageant la même variable doivent utiliser la même modalité pour renseigner le total. On le vérifie en regardant les données.

any(turnover_act_cj$CJ == "Total")
[1] TRUE
any(turnover_nuts_size$NUTS == "Total")
[1] TRUE
any(turnover_nuts_cj$NUTS == "Total")
[1] TRUE
any(turnover_nuts_cj$CJ == "Total")
[1] TRUE

Ici il n’y a pas de problème puisque toutes les variables en commun ont une même modalité représentant les marges : “Total”.


4.2 Poser le secret primaire sur chacun des tableaux

Les règles de secret appliquées ici correspondent aux règles spécifiques aux statistiques entreprises. Pour en savoir plus sur les différentes règles existantes, reportez-vous à l’annexe 11.

liste_4tabs <- liste_4tabs %>%
  purrr::map(
    function(df){
      df %>%
        mutate(
          is_secret_freq = N_OBS > 0 & N_OBS < 3,
          is_secret_dom = (MAX != 0) & (MAX > TOT*0.85),
          is_secret_prim = is_secret_freq | is_secret_dom
        )
    }
  )

Ce code est expliqué à l’annexe 12.

4.3 Calculer le nombre de cellules en secret primaire

Avant de passer à l’étape suivante il est important de prendre connaissance de la quantité de secret primaire présent dans les tableaux. En effet, s’il y a beaucoup de secret primaire alors il y aura sans doute beaucoup de secret secondaire et donc vraisemblablement trop de cellules en secret. Dans ce cas-là, il est intéressant pour réduire le secret primaire de changer les tableaux en regroupant des variables ou des modalités.

liste_4tabs %>% purrr::walk(function(tab) count(tab, is_secret_prim) %>% print())
# A tibble: 2 × 2
  is_secret_prim     n
  <lgl>          <int>
1 FALSE            337
2 TRUE              77
# A tibble: 2 × 2
  is_secret_prim     n
  <lgl>          <int>
1 FALSE            346
2 TRUE              60
# A tibble: 2 × 2
  is_secret_prim     n
  <lgl>          <int>
1 FALSE            388
2 TRUE              72
# A tibble: 2 × 2
  is_secret_prim     n
  <lgl>          <int>
1 FALSE            387
2 TRUE              65

4.4 Poser le secret secondaire avec tab_multi_manager()

La fonction tab_multi_manager() requiert les arguments suivants :

  • list_tables : liste de tables à protéger

  • list_explanatory_vars : liste des noms des variables de croisements présentes dans la liste des tables à protéger dans la table;

  • dir_name : le nom du répertoire qui contiendra tous les fichiers créés, s’il n’existe pas, il sera créé (ex : dir_name = "my_directory").

  • hrc : un vecteur nommé spécifiant le chemin vers le fichier .hrc pour chaque variable hiérarchique (ex : c(ACTIVITY = “chemin_vers_fichier/act.hrc”, NUTS = “chemin_vers_fichier/nuts.hrc” )).

  • alt_hrc : une liste nommée utile pour traiter les hiérarchies non emboîtées. Les noms de la liste sont les noms des tableaux pour lesquelles une autre hiérarchie (non emboîtée en général) doit être utilisée (ex : si T1 et T2 ont une variable explicative, appelée ACTIVITY, et la même variable de réponse, mais la variable ACTIVITY n’a pas la même hiérarchie dans les les deux tables). Supposons que les hiérarchies (act1.hrc et act2.hrc) ne sont pas emboîtées. Dans ce cas, nous écrivons les deux arguments comme suit :

    • hrc = c(ACTIVITY = "path_to_file/act_1.hrc") : par défaut, cette hiérarchie sera utilisée pour la variable ACTIVITY.

    • alt_hrc = list(T2 = c(ACTIVITY = "chemin_vers_fichier/act_2.hrc")) dans la table T2, la hiérarchie alternative sera utilisée.

  • totcode : le code du total pour chaque variable explicative. Il est recommandé d’utiliser le même code de total pour chaque variable. Si par exemple le code est “Total” pour toutes les variables. La syntaxe suivante est autorisée : totcode = “Total”. Sinon, l’input attendu est une liste spécifiant le code total pour chaque variable explicative (ex : totcode = list(ACTIVITY = “Total”, NUTS = “FR”, SIZE = “Ensemble”, CJ = “Total”))

Attention : Si les totaux ne sont pas dans la table, ils seront calculés par Tau-Argus, mais ils ne seront pas éligibles pour la suppression primaire. Il est donc nécessaire de les fournir dans la table de départ.

  • alt_totcode : une liste nommée pour les codes de totaux alternatifs (voir alt_hrc pour l’utilisation).

  • value : le nom de colonne de la variable de réponse dans les tableaux, il DOIT être identique pour chaque table (ex : valeur = “turnover”). Valeur par défaut : “value”.

  • freq : le nom de colonne de la variable de fréquence dans les tableaux, il DOIT être le même nom pour chaque tableau (ex : freq = “frequency”). Valeur par défaut : “freq”.

  • secret_var : le nom de la variable booléenne spécifiant le secret primaire dans les tables, il DOIT être le même nom pour chaque table (ex : secret_var = “is_secret_prim”). Valeur par défaut : “is_secret_prim”.

masq_4tabs <- tab_multi_manager(
    list_tables = liste_4tabs,
    list_explanatory_vars = liste_vars_4tabs,
    dir_name = "tauargus_files/4tabs",
    hrc = list(ACTIVITY = act_hrc_file, NUTS = nuts_hrc_file),
    totcode = "Total",
    value = "TOT",
    freq = "N_OBS",
    secret_var = "is_secret_prim"
)

4.5 Analyser les résultats

Analyser le journal

La fonction tab_multi_manager() fournit un journal décrivant l’ensemble des itérations réalisées lors du processus de protection. Il s’agit du fichier journal.txt dans le répertoire mentionné dans dir_name.

Pour chaque étape, sont indiqués :

  • Le tableau sur lequel est posé sur le secret secondaire ;
  • Le bilan du secret posé sur ce tableau ;
  • Le nombre de cellules communes (c’est-à-dire appartenant à plusieurs tableaux) touchées.

L’ensemble des cellules communes est listé en fin de processus.

Bilan du secret

L’objet retourné par la fonction tab_multi_manager() est une liste contenant les mêmes tables que la liste placée en input auxquelles sont ajoutés les résultats des différentes étapes de la pose du secret secondaire. Ainsi, la dernière variable de chaque tableau permet de déterminer le statut final de chaque cellule.

Ce code crée une variable statut_final renvoyant les codes de la norme européenne :

-   `A` les cellules en secret primaire à cause de la règle de
    fréquence
-   `B` les cellules en secret primaire à cause de la règle de
    dominance
-   `D` les cellules concernées par le secret secondaire
-   `V` les cellules non touchées par le secret, c'est-à-dire les
    cellules qui pourront être diffusées
masq_4tabs <- masq_4tabs %>% 
  purrr::map(
    function(tab){
      tab %>% 
        rename_with(~"is_secret_final", last_col()) %>% 
        mutate(
          statut_final = case_when(
            is_secret_freq ~ "A",
            is_secret_dom ~ "B",
            is_secret_final ~ "D",
            TRUE ~ "V"
          )
        )
    }
  )
str(masq_4tabs)
List of 4
 $ act_size :'data.frame':  414 obs. of  14 variables:
  ..$ ACTIVITY       : chr [1:414] "01" "01" "02" "02" ...
  ..$ SIZE           : chr [1:414] "Total" "tr1" "Total" "tr1" ...
  ..$ N_OBS          : int [1:414] 18 18 387 381 6 1 1 4 4 84 ...
  ..$ TOT            : num [1:414] 853 853 43623 35503 8120 ...
  ..$ MAX            : num [1:414] 303 303 6212 6212 4812 ...
  ..$ is_secret_freq : logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ is_secret_dom  : logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ is_secret_prim : logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ is_secret_1    : logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ is_secret_2    : logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ is_secret_3    : logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ is_secret_4    : logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ is_secret_final: logi [1:414] FALSE FALSE FALSE FALSE FALSE TRUE ...
  ..$ statut_final   : chr [1:414] "V" "V" "V" "V" ...
 $ act_cj   :'data.frame':  406 obs. of  14 variables:
  ..$ ACTIVITY       : chr [1:406] "01" "01" "01" "02" ...
  ..$ CJ             : chr [1:406] "LL" "SP" "Total" "LL" ...
  ..$ N_OBS          : int [1:406] 9 9 18 240 147 387 1 1 1 3 ...
  ..$ TOT            : num [1:406] 435 418 853 27625 15998 ...
  ..$ MAX            : num [1:406] 263 303 303 6212 672 ...
  ..$ is_secret_freq : logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_dom  : logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_prim : logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_1    : logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_2    : logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_3    : logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_4    : logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_final: logi [1:406] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ statut_final   : chr [1:406] "V" "V" "V" "V" ...
 $ nuts_size:'data.frame':  460 obs. of  14 variables:
  ..$ NUTS           : chr [1:460] "FR10" "FR10" "FR10" "FR10" ...
  ..$ SIZE           : chr [1:460] "Total" "tr1" "tr2" "tr3" ...
  ..$ N_OBS          : int [1:460] 38462 37329 1096 37 19469 18919 529 21 2725 2649 ...
  ..$ TOT            : num [1:460] 33026385 13774596 7172793 12078996 19217180 ...
  ..$ MAX            : num [1:460] 3084242 1013320 513792 3084242 3084242 ...
  ..$ is_secret_freq : logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_dom  : logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_prim : logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_1    : logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_2    : logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_3    : logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_4    : logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_final: logi [1:460] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ statut_final   : chr [1:460] "V" "V" "V" "V" ...
 $ nuts_cj  :'data.frame':  452 obs. of  14 variables:
  ..$ NUTS           : chr [1:452] "FR10" "FR10" "FR10" "FR10" ...
  ..$ CJ             : chr [1:452] "LL" "PA" "SP" "Total" ...
  ..$ N_OBS          : int [1:452] 28705 1012 8745 38462 15372 983 3114 19469 1598 1 ...
  ..$ TOT            : num [1:452] 24151930 26238 8848217 33026385 13207770 ...
  ..$ MAX            : num [1:452] 1674878 5577 3084242 3084242 1674878 ...
  ..$ is_secret_freq : logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_dom  : logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_prim : logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_1    : logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_2    : logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_3    : logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_4    : logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ is_secret_final: logi [1:452] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ statut_final   : chr [1:452] "V" "V" "V" "V" ...

On peut ainsi dresser notre bilan par tableau :

masq_4tabs %>% 
  purrr::imap_dfr(
    function(tab, nom){
      tab %>% 
        count(statut_final) %>% 
        mutate(
          part = n/sum(n)*100,
          table = nom
        ) %>% 
        relocate(table)
    }
  )
       table statut_final   n      part
1   act_size            A  52 12.560386
2   act_size            B  25  6.038647
3   act_size            D  83 20.048309
4   act_size            V 254 61.352657
5     act_cj            A  35  8.620690
6     act_cj            B  25  6.157635
7     act_cj            D  88 21.674877
8     act_cj            V 258 63.546798
9  nuts_size            A  55 11.956522
10 nuts_size            B  17  3.695652
11 nuts_size            D  82 17.826087
12 nuts_size            V 306 66.521739
13   nuts_cj            A  45  9.955752
14   nuts_cj            B  20  4.424779
15   nuts_cj            D 101 22.345133
16   nuts_cj            V 286 63.274336