1  Premiers pas

Accès aux données en mode “population”

Pour simuler le comportement de long terme de la population active, Trajectoire en mode “population” nécessite l’usage de données soumises au secret statistique . Le calcul de pension pour des cas-types est, lui, indépendant de ces sources confidentielles.

Les données concernées sont: - EIC 2013 et 2017 - Appariement EIC - Pannel tous actifs 2013 et 2017 - EIR 2012 et 2016

Les autorisations d’accès sont données par le comité du secret statistique, qui se réunit quatre fois par an, sur présentation d’un projet motivé. Le calendrier des prochaines sessions est disponible ici mais il faut prévoir plusieurs mois pour un premier accès. Une copie de la demande doit être envoyée à drees-sol@sante.gouv.fr et les bases de données ci-dessus doivent toute être référencées, avec leur millésime.

Sur réponse postive, le Centre d’Accès Sécurisé aux Données (CASD) vous accompagnera pour accéder aux données. L’accès via le CASD est payant et Trajectoire nécessite au minimum 32 Go de mémoire vive pour une exécution sur l’EIR complet (et plutôt 64 Go pour travailler confortablement). Au 25/09/2023, une telle configuration pour un seul utilisateur coûtait 37€/mois pour le boitier d’accès sécurisé et 253+466=719€/mois pour la location de la machine virtuelle (source ; les prix sont fortement dégressifs après le premier utilisateur).

Nous travaillons an parallèle à construire des données synthétiques afin de pouvoir tester les fonctionalités de Trajectoire sans avoir accès à ces données confidentielles. Trajectoire offre en outre la possibilité de travailler sur un échantillon de l’EIC pour permettre l’usage de configurations matérielles plus faibles, sans perte notable de qualité (voir étape 2.30 pour une explication et section 1 pour un exemple).

1.1 Installation

L’installation de Trajectoire se fait soit depuis le Gitlab public de la Drees, soit depuis une copie locale sur le CASD. Le paquet trajectoire n’est pas sur le CRAN.

Pour l’installation de la version de développement voir la section contribuer.

devtools::install_gitlab("https://git.drees.fr/drees_code_public/modeles/trajectoire")
#TODO: choisir emplacement avec CASD
install.packages(
  "C:/Users/Public/Documents/trajectoire_0.1.tar.gz",
  type = "source"
)

Ensuite, Trajectoire peut être utilisé en chargeant le package normalement :

library(trajectoire)

1.2 Initialisation d’un projet

Un projet Trajectoire commence par l’appel à la fonction init(). Cette fonction crée :

  • un script R reprenant les éléments de cette introduction ;
  • un fichier de configuration au format YAML
  • un dossier _cache pour sauvegarder les résultats intermédiaires des calculs

De plus, la fonction init() exécute les premières étapes de Trajectoire. Indépendantes des carrières, ces étapes n’ont pas vocation à être réexécutées fréquemment.

1.3 Utilisation en mode cas-type

Commençons avec un exemple et modélisons la carrières et les droits d’une personne salariée du privé, en faisant l’hypothèse d’une carrière entièrement au SMIC.

1.3.1 Préparation

Dans ce cas simple, deux bases sont à remplir :

  1. les données à caractère individuel dans dtId ;
  2. et les données de carrière dans dtIdAnEtat.

Commençons par les données individuelles : identifiant, date de naissance, sexe, âge de décès, nombre d’enfants et date de liquidation des droits à la retraite. Les dates sont supposées connues au mois près.

dtId <- data.table(
  id = "Françoise", # identifiant unique (libre)
  dateNaissance = anneeMois(aaaa = 1960, mm = 4), # avril 1960
  sexe = "Femme",
  ageMort = 86,
  nbEnfant = 0,
  dateLiq = anneeMois(aaaa = 2022, mm = 4) # avril 2022
)
  • id est un identifiant individuel unique arbitrairement au choix de l’utilisateur, par ex. "salariée du privé au SMIC", "59093xvf4", "cas-type 3" ou encore comme ici "Françoise"
  • dateLiq, la date de liquidation des droits à la retraite, peut être renseignée ici lorsque celle-ci est la même dans toutes les caisses ; c’est le cas ici puisque la personne ne cotise qu’au régime général

Pour la carrière, on renseigne les informations année par année. Le SMIC étant mis à jour au premier janvier de chaque année, on fera commencer la carrière de notre salariée au premier janvier 1980 et terminer le 31 décembre 2022.

dtIdAnEtat <- data.table(
  id = "Françoise",
  annee = 1980:2022, # de 1980 à 2022 (date de liquidation)
  etatTravail = "Salarie du prive non cadre", # voir ci-dessous
  remuneration = serieSmic(1980, 2022)
)

Le revenu est le revenu annuel, même pour la dernière année1. La fonction utilitaire serieSmic permet de récupérer le revenu annuel au SMIC pour les années sélectionnées2. L’état travaillé "Salarie du prive non cadre" est un des états possibles dans la modélisation de Trajectoire. Voir ici pour la liste des états possibles.

1.3.2 Calcul

La fonction calculePension() calcule les droits à la retraite sur la base de la carrière déclarée et des caracteristiques de la personne. calculePension(), comme la fonction lancerModele(..., mode='cas-type') qu’elle enveloppe, exécutent une à une les étapes de la modélisation.

resultats <- calculePension(dtId = dtId, dtIdAnEtat = dtIdAnEtat)

Les étapes du calcul des pensions occupent la plus grande partie de la présente documentation. La liste des étapes exécutées en mode “cas-types” par est accessibles ainsi :

etapes[ dansCasType==TRUE ]

1.3.3 Résultats

Une fois les calculs effectués, il est recommandé de “déplier” les résultats dans l’environnement de travail. Cela permet d’écrire par exemple simplement dtIdCaisse au lieu de resultats$dtIdCaisse.

list2env(resultats, envir = globalenv()) 

Les résultats sont organisés dans plusieurs tables, présentées ci-dessous. Par mi elles, on retiendra notamment :

  • dtIdPensionnes pour les données par pensionné.es (les personnes sans pension sont donc exclues)
  • dtIdCaisse pour les données par régime (deux dans notre exemple, le régime général et le régime complémentaire Agirc-Arco ; les pensions sont données brutes à la date de liquidation)
  • dtIdAnCaissePension pour les chroniques de pensions, c’est-à-dire les pensions touchées mensuellement jusqu’à la mort et où chaque ligne s’interprète ainsi : “L’année annee, pendant duree mois, la personne a touché une pension mensuelle de pension euros.”

Les autres tables contiennent des informations sur les salaires de référence pour les régimes en annuités (en euros courants à la date de liquidation ; dtIdCaisseSalaireReference), les données des régimes de base (par opposition aux régimes complémentaires ; dtIdCaisseBase) ou les régimes avec modulation temporaire des pensions (dtIdCaisseModulationTemporaire). dtId reprend les données fournies en entrée mais contient également une colonne type qui permet d’identifier les personnes non inclues dans les autres tables (personnes décédées avant l’ouverture de leurs droits, personnes n’ayant droit à aucune pension, etc.).

La fusion des régimes Agirc et Arrco à partir de 2019 est prise en compte, et tout se passe comme si l’individu avait toujours cotisé au régime unifié Agirc-Arrco.

Les tables dtIdAnCaisse, pour les régimes de base, et dtIdAnCaisseComplementaire, pour les régimes complémentaires, contiennent des informations annuelles par caisse sur les droits acquis au cours de la carrière.

1.3.4 Personne cotisant dans plusieurs caisses

Pour une personne ayant cotisé dans plusieurs caisses au cours de sa carrière, on spécifie simplement la caisse de cotisation. Prenons l’exemple d’un homme ayant travaillé dans le public, tout d’abord comme contractuel, puis comme fonctionnaire d’administration centrale.

dtId <- data.table(
  id = "Grégoire",
  dateNaissance = anneeMois(aaaa = 1958, mm = 1), # janvier 1958
  sexe = "Homme",
  ageMort = 78,
  nbEnfant = 3,
  dateLiq = anneeMois(aaaa = 2021, mm = 9) # septembre 2021
)

Par simplicité, on suppose que cette personne a également eu une carrière au SMIC.

dtIdAnEtat <- data.table(
  id = "Grégoire",
  annee = 1978:2021,
  etatTravail = c(
    rep("Contractuel de la FP", 15), # 15 années contractuel de la fonction publique
    rep("FPE", 29)                   # 29 années fonction publique d'État
  ), 
  remuneration = serieSmic(1978, 2021)
)

Par contre, dans le public, une part de la rémunération est assurée sous forme de primes, qui rentrent dans le calcul de la pension complémentaire (RAFP), mais pas de la pension de base (SRE). Il est donc nécessaire de préciser le montant de ces primes. Supposons que le taux de prime soit de 5 % :

dtIdAnCaisseFonctionnaire <- data.table(
  id = "Grégoire",
  annee = (1978+15):2021, # uniquement pour les années dans la fonction publique
  caisse = "SRE", 
  primes = 0.05*serieSMPT(1978+15,2021)
)

Le calcule des pensions utilise cette information spécifique aux fonctionnaires :

resultats <- calculePension(
  dtId = dtId, dtIdAnEtat = dtIdAnEtat,
  dtIdAnCaisseFonctionnaire = dtIdAnCaisseFonctionnaire # nouveau !
)

Les résultats respectent le même format que précédemment. On pourra vérifier que, par exemple dans dtIdAnCaisseComplementaire, Grégoire cotise bien à l’Ircantec dans un premier temps (caisse complémentaire des contractuels de la fonction publique) puis au RAFP ensuite (complémentaire de la fonction publique).

list2env(resultats, envir = globalenv())
<environment: R_GlobalEnv>

1.3.5 Modéliser plusieurs cas simultanément

Pour modéliser plusieurs cas-types, qu’il s’agisse de personnes distinctes ou de variantes concernant la même personne, il est possible de présenter l’ensemble des données en une seule fois. Prenons l’exemple d’une femme dont nous souhaiterions savoir comment le nombre d’enfant influence la pension.

# Ce tableau comporte 4 lignes, donc 4 cas-types :
dtId <- data.table(
  id = c("Sans enfant", "1 enfant", "2 enfants", "3 enfants"), # 4 valeurs
  dateNaissance = anneeMois(aaaa = 1956, mm = 8), # août 1956
  sexe = "Femme",
  ageMort = 85,
  nbEnfant = c(0, 1, 2, 3), # 4 valeurs
  dateLiq = anneeMois(aaaa = 2024, mm = 4) # janvier 2024
)

On suppose que la carrière de cette personne est identique sans ou avec un enfant, mais qu’elle diminue son temps de travail à 90% à partir du premier enfant, puis à 80% à partir du troisième. Supposons que cette femme est une cadre du privé gagnant 2,5 fois le SMIC3.

dtIdAnEtat <- rbind(
  data.table(
    id = "Sans enfant",
    annee = 1956:2024,
    etatTravail = "Salarie du prive cadre",
    remuneration = 2.5*serieSmic(1956, 2024)
  ),
  data.table(
    id = "1 enfant",
    annee = 1956:2024,
    etatTravail = "Salarie du prive cadre",
    remuneration = 2.5*serieSmic(1956, 2024)
  ),
  data.table(
    id = "2 enfants",
    annee = 1956:2024,
    etatTravail = "Salarie du prive cadre",
    remuneration = c(
      2.5*serieSmic(1956, 1956+30-1),
      0.9*2.5*serieSmic(1956+30, 2024) # 2e enfant à 30 ans
    )
  ),
  data.table(
    id = "3 enfants",
    annee = 1956:2024,
    etatTravail = "Salarie du prive cadre",
    remuneration = c(
      2.5*serieSmic(1956, 1956+30-1),
      0.9*2.5*serieSmic(1956+30, 1956+32-1),
      0.8*2.5*serieSmic(1956+32, 2024) # 3e enfant à 32 ans
    )
  )
)

On procède ensuite comme précédemment :

resultats <- calculePension(dtId = dtId, dtIdAnEtat = dtIdAnEtat)
list2env(resultats, envir = globalenv())
<environment: R_GlobalEnv>

On peut maintenant comparer le résultats, par exemple ici les pensions mensuelles moyennes :

dtIdAnCaissePension |>
  dplyr::group_by(id, annee) |>
  dplyr::summarise(pension=sum(pension*duree)/sum(duree)) |>
  dplyr::mutate(id = factor(id, levels=dtId$id)) |>
  ggplot(aes(x=annee,y=pension)) +
  geom_line(
    aes(colour=id, linetype=id), size=1,
    position=position_jitter(width=0, height=2) # pour voir la ligne du dessous
  ) +
  scale_y_continuous(labels = scales::label_number(suffix = " €")) +
  scale_linetype_manual(
    values = c(
      "Sans enfant" = "solid",
      "1 enfant" = "longdash",
      "2 enfants" = "dashed",
      "3 enfants" = "dotted"
    )
  ) +
  labs(
    x = NULL, y = NULL, title="Pension mensuelle moyenne ", colour=NULL, linetype=NULL) +
  theme_minimal()

1.4 Utilisation en mode population

Accès aux données en mode “population”

Pour simuler le comportement de long terme de la population active, Trajectoire en mode “population” nécessite l’usage de données soumises au secret statistique . Le calcul de pension pour des cas-types est, lui, indépendant de ces sources confidentielles.

Les données concernées sont: - EIC 2013 et 2017 - Appariement EIC - Pannel tous actifs 2013 et 2017 - EIR 2012 et 2016

Les autorisations d’accès sont données par le comité du secret statistique, qui se réunit quatre fois par an, sur présentation d’un projet motivé. Le calendrier des prochaines sessions est disponible ici mais il faut prévoir plusieurs mois pour un premier accès. Une copie de la demande doit être envoyée à drees-sol@sante.gouv.fr et les bases de données ci-dessus doivent toute être référencées, avec leur millésime.

Sur réponse postive, le Centre d’Accès Sécurisé aux Données (CASD) vous accompagnera pour accéder aux données. L’accès via le CASD est payant et Trajectoire nécessite au minimum 32 Go de mémoire vive pour une exécution sur l’EIR complet (et plutôt 64 Go pour travailler confortablement). Au 25/09/2023, une telle configuration pour un seul utilisateur coûtait 37€/mois pour le boitier d’accès sécurisé et 253+466=719€/mois pour la location de la machine virtuelle (source ; les prix sont fortement dégressifs après le premier utilisateur).

Nous travaillons an parallèle à construire des données synthétiques afin de pouvoir tester les fonctionalités de Trajectoire sans avoir accès à ces données confidentielles. Trajectoire offre en outre la possibilité de travailler sur un échantillon de l’EIC pour permettre l’usage de configurations matérielles plus faibles, sans perte notable de qualité (voir étape 2.30 pour une explication et section 1 pour un exemple).

1.4.1 Lancer une simulation

Trajectoire a comme situation de référence la législation courante, à quelques simplifications près. Pour lancer ce “scénario de référence”, utilisons la fonction lancerModele(). Sur le CASD, certaines étapes ne sont pas effectuées par manque d’une connexion Internet. Les données correspondantes sont récupérées depuis le package lui-même mais peuvent ne pas être à jour.

Attention! Le temps d’exécution de Trajectoire se compte en demi-heures ! On peut réduire la finesse du modèle avec tauxReduction=..., ce qui divise d’autant le nombre de trajectoires simulées.

lancerModele(tauxReduction = 10)

1.4.2 Principe des variantes

Pour créer une variante simple, l’idée est d’intervenir au niveau d’une ou plusieurs étapes de Trajectoire. Concevoir une variante constructive, qui implémente de nouveaux dispositifs, demande une connaissance relativement fine du système des retraites et de son implémentation dans Trajectoire. Désactiver un dispositif existant pour en mesurer l’impact est souvent plus facile.

Pour concevoir une variante, il faut : - identifier les étapes concernées, soit via la documentation, soit via la table etapes - identifier si les modifications souhaitées suppriment, remplacent ou annulent les étapes identifiées - écrire les fonctions qui effectuent ces changements ; dans certains cas simples, il suffit de changer les options des fonctions existantes - dans un script, utiliser lancerModele(premiereEtape=..., derniereEtape=..., scenario=<nom de la variante>) pour lancer les séries d’étapes non modifiées, et exécuter les étapes modifiées via des scripts

Dans les sauvegardes, Trajectoire crée un embranchement à parti de la première étape relancée avec un nouveau nom de scénario. Les résultats du scénario central sont alors réutilisés lorsque des étapes plus tardives font appel aux résultats des premièrs étapes. Par exemple, une variante sur la durée de cotisation permettant d’atteindre le taux plein n’a de conséquence qu’en fin de modélisation. Aussi, cette variante réutilisera la modélisation des carrières du scénario central. Pour cette raison, le tirage des aléas pour la modélisation est cenrtralisée en début de modélisation, pour que les individus restent comparables d’un scénario à l’autre.

Des exemples simples sont donnés ci-dessous. Nous contacter pour des variantes plus complexes. En particulier, un mécanisme non documenté de “cascade” de scénarios permet de représenter les “couches” successives d’une variante complexe.

1.4.3 Inventer une variante législative simple

Imaginons que nous souhaitions évaluer le dimensionnement des dispositifs de prise en compte des carrières longues. Qui sont les personnes bénéficiaires et quel est le coût pour la collectivité ?

Avec Trajectoire, nous pouvons répondre à cette question en imaginant un monde contre-factuel sans prise en charge des carrrières longues, puis en comparant cette variante avec la simulation standard.

Voici comment procéder. Tout d’abord on définit le nom de notre variante :

# nom de la variante
varianteLegislative <- "contreFactuelSansCarrieresLongues"

Ensuite on vient supprimer l’effet du dispositif qui nous intéresse. Ici, on repère l’étape qui détermine les carrières longues selon la législation puis, à la sortie de cette étape, on supprime toutes les personnes identifiées comme ayant vécu une longuer carrière. On relance ensuite le modèle à partir de cette étape. Le début du modèle, lui, reste identique au scénario central et n’est donc pas réexécuté !

# identifiant de l'étapes où intervenir
idCarrieresLongues <- etapes[fonction=='carrieresLongues', id]

# à la *sortie* de cette étape, on a une table
# qui recense toutes les personnes éligibles au dispositifs
# de prise en compte desw carrières longues
charge(
  dtIdRacl,
  # par défaut, charge() récupère les tables existant *en entrée*
  # d'où l'utilisation de idCarrieresLongues + 1 pour les tables *en sortie*
  etape = idCarrieresLongues + 1, 
  # tauxReduction = 10 est obligatoire pour savoir dans quel dossier
  # aller chercher la table (même valeur que dans lancerModele() ci-dessus)
  tauxReduction = 10
)

# on vide complètement cette table
# afin de supprimer toutes les personnes identifiées comme 'carrière longue'
# et on la sauvegarde un nouvel embranchement (scenario = varianteLegislative),
dtIdRacl <- dtIdRacl[FALSE]
sauvegarde(
  dtIdRacl,
  etape = idCarrieresLongues,
  scenario = varianteLegislative,
  tauxReduction = 10
)

# enfin on reprend le modèle à partir de cette étape
# en restant sur le nouvel embranchement / scénario
lancerModele(
  premiereEtape = idCarrieresLongues+1,
  scenario = varianteLegislative,
  tauxReduction = 10
)

Ensuite on peut utiliser la fonction lancerVariancesVsReference() pour analyser les résultats de la simulation au regard de la simulation de référence. Par défaut, ce code produit un document au format HTML qui est par défaut placé dans un dossier sorties à la racine du projet.

lancerVariantesVsReference(
  listeNomsVariantes = varianteLegislative,
  tauxReduction = 10
)
charge(paramModele)
paramModele$anneeEic

Notons que le “présent” de Trajectoire est la dernière année observéee de l’EIC (paramModele$anneeEic) et que par défaut il n’existe pas de date d’application d’une réforme. Toute réforme décrite dans Trajectoire s’applique sans délai à partir de cette date. Dans notre exemple, cela signifie que les dispositifs de carrière longue sont supprimés à partir de paramModele$anneeEic.

En revanche, les variantes ciblant des générations particulières, pour autant que ces générations soient en 2017 encore suffisamment loin de l’âge de la retraite, sont structurellement immunisée, puisqu’elles s’appliquent au fur et à mesure que ces générations arrivent à l’âge de la retraite.

Absence d’adaptation et d’anticipations

La plupart des événements et comportements modélisés dans Trajectoire restent fixes, indépendemment de la législation liée aux retraites. En particulier, les trajectoires sur le marché du travail restent les mêmes dans la simulation standard et dans la simulation contre-factuelle ; seule change l’éventuelle date du départ à la retraite. (Rappelons que les individus possèdent une trajectoire professionnelle virtuelle jusqu’à 70 ans justement pout permettre des telles comparaisons à carrière fixée.) Par ailleurs, la date départ est obtenue par un calcul probabiliste à la date \(t\), sans anticipation de législation. Pour revenir à notre exemple, cela signifie que dans Trajectoire, les personnes de 18 ans font leur arbitrage étudier/travailler de façon indépendante de l’existence d’un dispositifs de prise en charge des carrières longues. En revanche, une fois à la fin de leur carrière, la date exacte de leur départ est recalculée dans le monde “sans carrières longues” puisque les conditions particulières (date d’ouverture des droits, montant des pensions) ont changé.

1.4.4 Exécuter une variante macroéconomique simple

Quel est l’impact des hypothèses de croissance sur la santé du système de retraite ? Une hausse ponctuelle du chômage se répercute-t-elle durablement dans le niveau des retraites ? Quels sont les perdants et les gagnants d’une moindre inflation ? Trajectoire permet de simuler ce type de scénarios.

Dans Trajectoire, la croissance économique est captée via la croissance des revenus du travail, ou salaire moyen par tête (SMPT), en supposant un partage constant de la croissance entre capital et travail. La croissance future est anticipée dans des variantes du COR, desquelles Trajectoire est tributaire. Ces variantes consistent généralement en une phase de moyen terme reprenant les projections du plan de stabilité du ministère du budget, suivi d’une transition vers des projections de long terme stables.

Le taux de chômage impacte les effectifs de cotisants, ici aussi contraints par les scénarios de prévision du COR. L’inflation, elle, peut être librement choisie dans la mesure où son impact se limite à la revalorisations de certains seuils et prestations.

varianteEconomique <- "chomageFaibleCroissanceFaible"
charge(paramModele)
paramModele$hypChomage <- "Chô 5%"
# cette variante doit exister dans les fichiers d'hypothèses du COR
# system.file("extdata", "cor", paramModele$fichierCorCotisant, package='trajectoire')
paramModele$hypSmpt    <- 0.7
# cette variante doit exister dans les fichiers d'hypothèses du COR
# system.file("extdata", "cor", paramModele$fichierCorSalairePrix, package='trajectoire')
sauvegarde(paramModele, scenario = varianteEconomique, etape="00.00")

lancerModele(
  # on relance depuis la première étape à partir de laquelles ces
  # hypothèses ont des conséquences
  premiereEtape = etapes[fonction %in% c(
    "prepareCibles",  # effectifs par secteurs, dépend du chômage
    "choixHypSmptCor" # choix de l'hyp de salaire
  ), min(id)],
  scenario = varianteEconomique,
  tauxReduction = 10
)

1.4.4.1 Absence de rétroaction macroéconomique

Trajectoire n’est pas un modèle macroéconomique, et à ce titre nous ne vérifions pas la cohérence des projections ; cette vérification incombe dès lors à l’utilisateur. Trajectoire ne connaît aucune notion de “demande de travail”, et le nombre de cotisants est fixé uniquement par les projections du Conseil d’orientation des retraites (COR), qui connaît une poignée de variantes démographiques et économiques. Ainsi, le taux de chômage n’influence que les cibles annuelles d’effectifs de cotisants. La croissance économique ne joue un rôle que via la croissance des salaires. Enfin, l’inflation ne rentre en compte que pour la revalorisation des pensions et des valeurs législatives de référence.

1.4.5 Imaginer une variante démographique simple

Combien de pensions devra-t-on verser lors d’un emballement de l’immigration ? Quelle soutenabilité fasse à une baisse de la fécondité ? De la même façon que les variantes économiques, les variantes démographiques les plus aisées à modéliser sont celles anticipées par le COR, et qui définissent les cibles annuelles de cotisants utilisées dans Trajectoire.

En construction

  1. Dans le privé, ce salaire ne rentre pas en compte pour le calcul des meilleures années, et n’est utile que pour valider des trimestres.↩︎

  2. Voir ici pour les hypothèse de prolongement du SMIC.↩︎

  3. On suppose en particulier que cette personne est trop riche pour bénéficier du dispositif d’AVPF (qui compenserait le temps partiel pour enfant par des salaires virtuels au SMIC) mais ne dépasse cependant pas les plafonds d’indemnité journalière de la Caisse Nationale d’Assurance Maladie pour indemniser les congés parentaux.↩︎