Au cours de cette séquence, nous aborderons la notion de programmation fonctionnelle. En particulier, nous découvrirons comment l’utilisation de fonctions rend l’analyse plus organisée et facile à comprendre. Nous traiterons en profondeur les sujets suivants :
Environnements : Les environnements sont des structures de données qui stockent des associations entre des noms et des valeurs. Ils sont utilisés pour gérer la portée des variables.
Programmation fonctionnelle : Nous aborderons les notions d’argument par défaut, de nombre arbitraire d’arguments et de certains opérateurs tels que {{}} permettant de gérer des expressions passées en argument
Pour l’ensemble de la formation, nous travaillerons en mode projet et utiliserons SSP Cloud. Une documentation est disponible ici.
1.2 Mise en place de l’environnement
Maîtriser les fonctions
Formation expertise
Créer un projet “R_Expertise”
Créer les dossiers et sous-dossiers pour structurer l’environnement de travail
# Import donnees ---------------------------------------------------------------revenus_dep_2014<-telechargerDonnees("FILOSOFI_DEP", date =2014, telDir =PATH_INPUT)
1.4 Environnements
Maîtriser les fonctions
Formation expertise
Les environnements sont des structures de données qui stockent des associations entre des noms et des valeurs. En R, chaque objet a un environnement associé qui détermine la portée de cet objet, c’est-à-dire où il peut être utilisé. Les environnements sont essentiels pour comprendre la portée des variables, les fonctions et la gestion de l’espace de travail.
Par défaut, on est dans l’environnement global, R_GlobalEnv. Lorsque l’on écrit y <- 1, on assigne l’entier 1 au nom y dans l’environnement global. Cette variable est alors accessible via le nom y.
1.5 Environnements 2/2
Maîtriser les fonctions
Formation expertise
La plupart du temps, on ne crée pas explicitement des environnements mais ils sont la conséquence de l’utilisation de fonctions. Il y a plusieurs types d’environnements associés à une fonction, les principaux étant :
L’enclosing environment : il s’agit de l’environnement où la fonction a été définie
L’environnement d’exécution : chaque fois que la fonction est appelée, un environnement est créé dans le cadre de l’exécution de la fonction
L’environnement dans lequel a été appelée la fonction accessible par parent.frame()
1.6 Enclosing environment
Maîtriser les fonctions
Formation expertise
Lorsque l’on définit une fonction, elle conserve une référence à l’environnement dans lequel elle est créée, qu’on appelle enclosing environment. Une fonction définie dans l’environnement global peut accéder aux variables définies dans l’environnement global, même si ces variables ne sont pas explicitement passées comme arguments à la fonction.
La grande différence entre une fonction de l’utilisateur et une fonction d’un package est leur enclosing environment :
y<-1f<-function(x){return(x+y)}# La variable y est accessible par la fonction f# le fonctionnement d'une fonction d'utilisateur peut être # dangereux car son enclosing environment est l'environnement global modifiableenvironment(f)
<environment: R_GlobalEnv>
# le fonctionnement d'une fonction de package est bien plus# maîtrisé car son enclosing environment est verrouilléenvironment(dplyr::filter)
<environment: namespace:dplyr>
1.7 Environnement d’exécution 1/4
Maîtriser les fonctions
Formation expertise
Chaque fois qu’une fonction est appelée, un environnement est créé pour exécuter les instructions.
y<-1# on exécute f pour x = 1res<-f(1)res
[1] 2
L’environnement est nouveau à chaque fois, ce qui crée une certaine indépendance entre les appels successifs.
1.8 Environnement d’exécution 2/4
if(exists("a")){rm(a)}f<-function(){if(!exists("a")){message("Définition de a")a<-1}else{a<-a+1}return(a)}f()# a est créé dans l'environnement d'exécution de la fonction
[1] 1
f()# La variable précédemment créée n'existe pas dans le nouvel environnement d'exécution
[1] 1
a<-5f()# a est trouvé dans l'enclosing environment et est donc incrémenté dans l'environnement d'exécution
[1] 6
f()# L'incrémentation précédente n'est pas prise en compte dans le nouvel environnement d'exécution
[1] 6
a# L'environnement global n'a pas été modifié
[1] 5
1.9 Environnement d’exécution 3/4
Les environnements ont un “environnement parent”, ce qui permet d’accéder aux noms dans l’environnement parent. Pour les environnements d’exécution, il s’agit de l’enclosing environment, ce qu’on peut constater dans l’exemple précédent.
Si l’on veut modifier l’environnement global avec une fonction, il faut explicitement désigner l’environnement dans lequel on veut assigner la valeur. C’est en général peu recommandé.
if(exists("a")){rm(a)}f<-function(){if(!exists("a")){message("Définition de a")assign("a", 1, envir =.GlobalEnv)}else{assign("a", a+1, envir =.GlobalEnv)}return(a)}f()# a est créé dans l'environnement global
[1] 1
f()# La variable précédemment créée est accessible et est donc incrémentée
[1] 2
1.10 Environnement d’exécution 4/4
On constate que la fonction garde une référence à l’enclosing environment et non une copie de l’état de l’environnement au moment de sa définition. Ainsi, les modifications de l’enclosing environment postérieures à la définition de la fonction (en l’occurrence, la définition de a) sont prises en compte dans les appels subséquents. C’est ce qu’on appelle une lazy evaluation, les variables ne sont évaluées que lorsque leur valeur est réellement nécessaire.
Alternativement, on aurait pu utiliser a <<- 1 pour créer a dans l’environnement parent, c’est à dire l’environnement global dans ce cas.
À l’inverse de assign, la fonction get permet de chercher une variable dans l’environnement spécifié.
La valeur de f(5,3) est 403 (30*13 + 13). Les variables x et y existent dans l’environnement d’exécution de la fonction puisque ce sont des arguments de la fonction, ce sont donc ces valeurs qui sont utilisées. En revanche, z n’existe pas dans l’environnement d’exécution, la fonction va donc accéder à la valeur située dans l’environnement global (enclosing environment).
1.12 Question 2
Maîtriser les fonctions
Formation expertise
Quelle est la valeur de x après avoir lancé la commande ?
1.13 Correction 2
Maîtriser les fonctions
Formation expertise
x reste toujours égale à la valeur assignée dans l’environnement global, à savoir 10, puisque les modifications ont eu lieu dans l’environnement d’exécution.
1.14 Les variables globales et locales {#globales_vs_locales .backgroundStandard}}
Maîtriser les fonctions
Formation expertise
Les variables globales sont accessibles depuis n’importe quel endroit de votre script ou de votre session R, tandis que les variables locales ont une portée limitée à une fonction ou à un environnement spécifique.
Les variables globales sont en fait les noms définis dans l’environnement global tandis que les variables locales existent dans des environnements à portée plus limitée (comme un environnement d’exécution).
1.15 Question 3
Maîtriser les fonctions
Formation expertise
# Package -------------------------------# install.packages("ggplot2")library(ggplot2)# Couleurs ---------------------------COULEUR_PRIMAIRE<-"#052337"COULEUR_SECONDAIRE<-"#39eab9"# Analyses ------------------------------creer_boxplot<-function(data, colonne){p<-ggplot(data, aes(x =1, y =data[[colonne]]))+geom_boxplot(color =COULEUR_PRIMAIRE, fill =COULEUR_SECONDAIRE)+geom_point(aes(y =median(data[[colonne]])), color =COULEUR_PRIMAIRE, size =3)+labs(title =paste("Boîte à moustaches de", colonne))+theme_minimal()print(p)}#creer_boxplot(revenus_dep_2014, "MED14")
Dans le code précédent, quelles sont les variables locales et globales ?
1.16 Correction 3
Maîtriser les fonctions
Formation expertise
Variables globales :
COULEUR_PRIMAIRE : C’est une variable globale, définie en dehors de la fonction creer_boxplot. Elle est accessible depuis n’importe quel endroit du script.
COULEUR_SECONDAIRE : C’est aussi une variable globale, définie en dehors de la fonction creer_boxplot.
creer_boxplot : C’est aussi une variable globale, que l’on peut appeler dans l’environnement global.
median, paste, print : Ce sont des fonctions de base, elles sont donc disponibles globalement dans l’environnement R.
ggplot, aes, geom_boxplot: Ce sont des objets/ fonctions provenant du package ggplot2.
Variables locales :
data : C’est une variable locale définie comme argument de la fonction creer_boxplot.
colonne : C’est aussi une variable locale définie comme argument de la fonction creer_boxplot.
p : C’est également une variable locale définie à l’intérieur de la fonction pour stocker le graphique produit.
1.17 Lazy evaluation
Maîtriser les fonctions
Formation expertise
La “Lazy Evaluation” (évaluation paresseuse) est un concept important en programmation fonctionnelle. Il signifie que l’évaluation d’une expression n’a lieu que lorsque le résultat est effectivement nécessaire, plutôt que d’être effectuée immédiatement. Cela permet d’optimiser les performances en évitant de calculer des valeurs inutiles.
Par exemple, les codes suivants ne retournent pas d’erreurs étant donné qu’ils n’évaluent que la partie TRUE de la condition.
if(TRUE){1}else{variable_inconnue}
[1] 1
if(FALSE){no_variable}else{1}
[1] 1
1.18 Question 4
Maîtriser les fonctions
Formation expertise
Quel est le résultat de la commande suivante (NB : || correspond à l’opérateur OU) ? Pourquoi ?
if(TRUE||variable_inexistante){1}
1.19 Correction 4
Maîtriser les fonctions
Formation expertise
Dans cette commande, l’opérateur logique || est utilisé, ce qui signifie “OU logique”. L’expression TRUE || variable_inexistante équivaut à TRUE car une seule des deux conditions doit être vraie pour que l’ensemble soit vrai. Les expressions sont évaluées de gauche à droite jusqu’à ce que le résultat soit connu ; variable_inexistante n’est donc jamais évalué.
Cela signifie que l’expression entre parenthèses est évaluée paresseusement, et la variable variable_inexistante n’est jamais évaluée car elle n’est pas nécessaire pour déterminer que l’ensemble est vrai.
Par conséquent, le bloc de code à l’intérieur du if est exécuté, et 1 est retourné.
1.20save & load
Maîtriser les fonctions
Formation expertise
Les fonctions save et load sont utilisées pour sauvegarder et charger des objets R, tels que des données, des fonctions, des variables, des graphiques, etc. Cela peut être utile lorsque vous souhaitez stocker des objets R pour une utilisation ultérieure, pour partager des données ou des résultats avec d’autres utilisateurs, ou pour économiser du temps en évitant de recalculer des objets coûteux en termes de temps.
La fonction save vous permet de sauvegarder des objets R dans un fichier avec l’extension “.RData” (ou “.rda”).
Attention
Pour les partages de données tabulaires on privilégiera le format universel Parquet.
1.21 Question 5
Maîtriser les fonctions
Formation expertise
Sauvegarder le dataframe revenus_dep_2014 et la fonction creer_boxplot dans un fichier “.RData” dans le dossier “Final” de “Data”.
Dans cet exemple, nous avons sauvegardé un objet creer_boxplot (une fonction) et un dataframe revenus_dep_2014 dans un fichier appelé ‘analyses_revenus_dep.RData’.
Maintenant, nous allons réinitialiser la mémoire de notre environnement grâce à la commande suivante :
Quel résultat va-t-on obtenir en lançant la commande suivante : print(revenus_dep_2014) ?
1.24 Correction 6
Maîtriser les fonctions
Formation expertise
Nous serons confrontés à une erreur étant donné que nous avons réinitialisé la mémoire de notre environnement. Heureusement, nous avons sauvegardé notre base de données et la fonction relative à son analyse que nous allons pouvoir récupérer grâce à la fonction load.
Note: La fonction save.image est similaire sauf qu’elle enregistre tous les objets de l’environnement global. On peut notamment s’en servir pour enregistrer certains objets en les sélectionnant via une regex :
rm(list =setdiff(ls(), ls(pattern ="^PATH")))# On supprime tout sauf les cheminsprint(paste("Number of models:", length(ls())))# On verifier le nombre d’objetssave.image(file =paste(PATH_FINAL, "chemins.RData", sep ="/"))# On sauve l’environnement
1.25 La fonction load
Maîtriser les fonctions
Formation expertise
La fonction load vous permet de charger des objets à partir d’un fichier “.RData” précédemment sauvegardé.
Il est important de mentionner cependant que le chargement d’objets depuis la fonction load se fait dans l’environnement global. Ainsi, si d’autres objets ont des noms identiques à ceux que l’on charge, ils seront écrasés.
x<-10# Création d'un objet dans l'environnement globalprint(x)
[1] 10
save(x, file =paste(PATH_FINAL, "objet_x.RData", sep ="/"))# Sauvegarde de l'objet x dans un fichierx<-20# Modification de la valeur de x dans l'environnement globalprint(x)# Affiche 20
[1] 20
# Chargement de l'objet x depuis le fichier dans un nouvel environnementnouvel_env<-new.env()load(paste(PATH_FINAL, "objet_x.RData", sep ="/"), envir =nouvel_env)print(nouvel_env$x)# Vérification de la valeur de x dans le nouvel environnement
[1] 10
print(x)# La valeur de x dans l'environnement global reste inchangée
[1] 20
1.26 Question 7
Maîtriser les fonctions
Formation expertise
Charger le fichier précédemment sauvergardé et vérifier que les objets sont bien présents dans la mémoire de notre environnement
Toute sauvegarde qui ne figure pas explicitement dans le script (par exemple lorsque RStudio propose à la fermeture de sauvegarder l’environnement) est fortement déconseillée. Il en est de même pour le chargement.
2 Programmation fonctionnelle
2.1 Introduction
Maîtriser les fonctions
Formation expertise
La programmation fonctionnelle est un concept de programmation. Il signifie que les fonctions peuvent être traitées comme des objets, passées en tant qu’arguments à d’autres fonctions, assignées à des variables, et retournées comme résultats. La programmation fonctionnelle favorise la modularité, la réutilisation du code et la clarté de ce dernier.
2.2 Les arguments par défaut
Maîtriser les fonctions
Formation expertise
Il est possible de spécifier des valeurs par défaut pour les arguments lors de la définition d’une fonction. Ces valeurs seront utilisées si aucune valeur n’est renseignée lors de l’appel de la fonction. Pour renseigner une valeur par défaut, la syntaxe suivante peut être utilisée :
f<-function(argument=valeur_defaut){# Corps de la fonction}
2.3 Question 8
Maîtriser les fonctions
Formation expertise
Créer une fonction qui calcule la moyenne de la part d’imposition (PIMP14) des départements dont le revenu médian (MED14) fait partie des plus élevés. Le pourcentage de départements à considérer est un argument dont la valeur par défaut est 50%.
2.4 Correction 8
Maîtriser les fonctions
Formation expertise
calculer_part_imposition<-function(data, pourcentage=0.5){# Calculer la part d'imposition moyenne pour ces observationspart_imposition_moyenne<-data%>%slice_max(MED14, prop =pourcentage)%>%summarise(mean(PIMP14))return(part_imposition_moyenne)}calculer_part_imposition(revenus_dep_2014)
calculer_part_imposition(revenus_dep_2014, 0.2)
2.5 Nombre arbitraire d’arguments
Maîtriser les fonctions
Formation expertise
Il est possible de créer des fonctions qui acceptent un nombre variable d’arguments, ce qui les rend flexibles et adaptables à différentes situations. Cette fonctionnalité est souvent utilisée lorsque nous ne savons pas à l’avance combien d’arguments nous devrons passer à une fonction.
Pour ce faire, on utilise l’opérateur ... comme argument de la fonction. Par ailleurs, il est d’usage de transformer les arguments fournis en liste dans le corps de la fonction pour que les arguments soient traités par la fonction. On utilise alors la commande arguments <- list(...).
2.6 Question 9
Maîtriser les fonctions
Formation expertise
Créer une fonction calculer_somme_personnes_departements prenant en compte un nombre arbitraire d’arguments et qui calcule le nombre total de personnes composant les ménages fiscaux (NBPERSMENFISC14) des départements (LIBGEO) utilisés comme arguments lors de l’appel de la fonction.
2.7 Correction 9
Maîtriser les fonctions
Formation expertise
calculer_somme_personnes_departements<-function(data, ...){# Les arguments passés à la fonction sont stockés dans la variable argumentsarguments<-list(...)# Filtrer le dataframe en fonction des départements spécifiésdata_filtre<-data%>%filter(LIBGEO%in%arguments)# Calculer la somme du nombre de personnes dans les ménages fiscauxsomme_personnes<-data_filtre%>%summarise(Somme_personnes =sum(`NBPERSMENFISC14`))# Renvoyer la somme calculéereturn(somme_personnes$Somme_personnes)}
2.8 Question 10
Maîtriser les fonctions
Formation expertise
Calculer le nombre total de personnes composant les ménages fiscaux des départements d’outre-mer présents dans la base de données.
2.9 Correction 10
Maîtriser les fonctions
Formation expertise
calculer_somme_personnes_departements(revenus_dep_2014, "Martinique", "La Réunion")
[1] 1193578
2.10 Les quosures
Maîtriser les fonctions
Formation expertise
Pour une même ligne de code, on peut distinguer deux choses : les expressions littéralement écrites et les valeurs de ces expressions.
ggplot2 utilise à la fois les valeurs stockées dans les colonnes MED14 et PIMP14 pour créer les points mais également littéralement le texte composant le code (qu’on appelle expression) pour désigner ces variables et ainsi afficher “MED14” et “PIMP14” en titres des axes.
Cette nuance peut être cruciale en particulier lorsque l’on travaille avec des fonctions.
2.11 Question 11
Maîtriser les fonctions
Formation expertise
Imaginons par exemple que l’on souhaite créer une fonction prenant en argument un nom d’une colonne de revenus_dep_2014 et qui renvoie le max de la colonne et que l’on écrit ce code suivant. Comment comprenez vous les résultats ?
Error in `summarise()`:
ℹ In argument: `max(var)`.
Caused by error:
! object 'MED14' not found
2.12 Correction 11
Maîtriser les fonctions
Formation expertise
Lorsque l’on appelle calculer_max("MED14"), l’argument var est remplacé par "MED14" et la partie de la fonction summarise(max(var)) est interprêtée comme summarise(max("MED14")). Le max du vecteur de texte "MED14"est "MED14".
Lorsque l’on appelle calculer_max(MED14), l’argument var est remplacé par l’objet MED14 de l’environnement global (à partir duquel on a appelé la fonction)… hors cet objet n’est pas défini dans l’environnement global ce qui résulte en une erreur.
2.13 Les quosures (suite)
Maîtriser les fonctions
Formation expertise
Une expression symbolique ou quosure permet de stocker une expression sous forme d’objet mais sans l’évaluer. Les quosures sont particulièrement utiles pour créer des fonctions génériques, prenant par exemple des noms de variable en argument.
Les fonctions quote et enquo sont utilisées pour créer des quosures à partir d’une expression R (pour quote) ou d’un argument (pour enquo qu’on utilise plutôt dans des fonctions). Il est ensuite possible de manipuler cette expression symbolique. Par exemple, la commande quote(1+2) est une quosure qui représente l’expression 1+2 mais pas la valeur 3
L’opérateur !! sert inversement à “déballer” une quosure pour qu’elle puisse être évaluée
Généralement, on n’a pas besoin de ces fonctions car {{}} (“curly curly”) permet de réaliser les 2 à la fois.
On a en fait déjà vu lors de la section sur les variables globales et locales comment traiter le cas où l’on souhaite renseigner le nom de la variable sous forme de texte via la syntaxe revenus_dep_2014[[var]]. Dans le cas des verbes dplyr, où les noms de colonnes ne sont pas directement accolés au dataframe, on peut utiliser .data pour faire référence au dataframe : .data[[var]]*
L’exemple suivant illustre l’intérêt des quosures dans des fonctions. Supposons qu’on dispose d’une fonction renvoyant la liste des N départements pour lesquelles le revenu médian prend les valeurs les plus élevées, N étant un argument de la fonction (nb_top) :
top_departements_revenu<-function(data, nb_top){# Filtrer le dataframe sur le top du revenu médian avec nb_top observationstop_departements<-data%>%arrange(desc(MED14))%>%filter(row_number()<=nb_top)%>%select(LIBGEO)%>%pull()return(top_departements)}# On applique la fonction pour obtenir le top 5 sur le revenu médian :top_departements_revenu(revenus_dep_2014, 5)
Supposons maintenant qu’on souhaite appliquer la même opération sur d’autres variables que le revenu médian. On souhaite pour cela ajouter la variable en argument de la fonction et remplacer MED14.
2.18 Correction 12
Maîtriser les fonctions
Formation expertise
On pourrait tenter de simplement remplacer MED14 par variable qui serait aussi un argument de la fonction, mais on obtiendrait alors une erreur car il n’existe pas de variable nommée “variable” dans le dataframe. C’est là que les quosures se révèlent utiles. L’opération souhaitée est possible avec l’opérateur {{}}
top_departements_variable<-function(data, nb_top, variable){# On transforme l'argument en quosurevariable<-enquo(variable)# Filtrer le dataframe selon la variable spécifiée sur nb_top observationstop_departements<-data%>%arrange(desc({{variable}}))%>%filter(row_number()<=nb_top)%>%select(LIBGEO)%>%pull()return(top_departements)}# On applique la fonction pour obtenir le top 5 sur le revenu médian :top_departements_variable(revenus_dep_2014, 5, MED14)
La fonction reframe est une fonction de la bibliothèque dplyr qui permet de transformer un dataframe en un autre dataframe en appliquant des fonctions à des colonnes du dataframe d’origine. Elle est similaire à la fonction summarise, mais avec deux différences principales :
reframe peut retourner un nombre arbitraire de lignes par groupe, tandis que summarise réduit chaque groupe à une seule ligne.
reframe renvoie toujours un dataframe non groupé, tandis que summarise peut renvoyer un dataframe groupé ou ligne par ligne, selon le scénario.
2.20 La fonction reframe
Maîtriser les fonctions
Formation expertise
Pour illustrer la puissance de reframe, considérons qu’on souhaite obtenir les quartiles du taux de pauvreté par département ;la fonction reframe permet d’obtenir le résultat souhaité :
Il est même possible d’appliquer le traitement par groupe ou sur plusieurs colonnes. Par exemple si l’on veut différencier les départements avec un revenu médian élevé de ceux avec un revenu médian faible :
Les fonctions infixes, également appelées opérateurs infixes, sont des fonctions qui permettent d’appliquer des opérations binaires en utilisant une notation infixe plus familière, comme +, -, *, /, etc. au lieu de la notation fonctionnelle standard. En d’autres termes, au lieu d’appeler une fonction avec des parenthèses, vous pouvez utiliser l’opérateur entre deux valeurs pour effectuer une opération.
Ainsi, les opérations +, -, *, et / font en réalité appel à une fonction en arrière plan. Par exemple, l’expression 1+3 appelle en fait la fonction + avec les arguments 1 et 3 : +(a, b). Il s’agit d’une infix function.
Il est alors possible de créer ses propres infix functions en utilisant la notation %...%, où ... est le nom que vous choisissez pour votre fonction.
Notes :
Il existe des infix functions bien connues qui utilisent cette syntaxe, comme %in% ou le pipe du tidyverse %>%
Il est important de ne pas utiliser de noms de fonctions déjà utilisées dans R afin d’éviter tout risque de conflits !
2.23 Infix function
Maîtriser les fonctions
Formation expertise
Par exemple, la fonction suivante est une infix function permettant de déterminer si une liste d’éléments est comprise dans une autre :
Créer une infix function permettant de comparer le taux de pauvreté (TP6014) de deux départements donnés
2.25 Correction 13
Maîtriser les fonctions
Formation expertise
`%comparer_pauvrete%`<-function(departement1, departement2){# Filtrer les données pour les deux départementsdata_departement1<-revenus_dep_2014%>%filter(LIBGEO==departement1)data_departement2<-revenus_dep_2014%>%filter(LIBGEO==departement2)# Récupérer les taux de pauvretétaux_pauvrete1<-data_departement1$TP6014taux_pauvrete2<-data_departement2$TP6014# Comparer les taux de pauvretéif(taux_pauvrete1>taux_pauvrete2){message(paste(departement1, "a un taux de pauvreté plus élevé que", departement2))}elseif(taux_pauvrete1<taux_pauvrete2){message(paste(departement2, "a un taux de pauvreté plus élevé que", departement1))}else{message("Les taux de pauvreté sont égaux pour", departement1, "et", departement2)}}"Puy-de-Dôme"%comparer_pauvrete%"Haut-Rhin"
3 Quiz
3.1 Question 1
Maîtriser les fonctions
Formation expertise
Comment appelle-t-on l’environnement où a été défini une fonction ?
A) Enclosing environment
B) Environnement d’exécution
C) Global environment
D) Running environnement
3.2 Correction 1
Maîtriser les fonctions
Formation expertise
La réponse correcte est la réponse :
A) Enclosing environment
3.3 Question 2
Maîtriser les fonctions
Formation expertise
On considère un script contenant la seule ligne de code suivante : a <- 1. Cette variable est :
A) Locale
B) Générale
C) Globale
3.4 Correction 2
Maîtriser les fonctions
Formation expertise
La réponse correcte est la réponse :
C) Globale
3.5 Question 3
Maîtriser les fonctions
Formation expertise
Quelle commande permet de sauvegarder l’objet a dans un fichier avec l’extension “.RData” (ou “.rda”) ?
A)save(a)
B)load(a)
C)quote(a)
3.6 Correction 3
Maîtriser les fonctions
Formation expertise
La réponse correcte est la réponse :
A)save(a)
3.7 Question 4
Maîtriser les fonctions
Formation expertise
Que renvoie la commande quote(1+2) ?
A)3
B)"1+2"
C)1+2
D)"3"
3.8 Correction 4
Maîtriser les fonctions
Formation expertise
La réponse correcte est la réponse :
C)1+2
3.9 Question 5
Maîtriser les fonctions
Formation expertise
Quelle syntaxe permet d’appeler des infix functions ?
A)#infix_function#
B)%infix_function%
C)^infix_function^
D)$infix_function$
3.10 Correction 5
Maîtriser les fonctions
Formation expertise
La réponse correcte est la réponse :
B)%infix_function%
4 Exercices Complémentaires
4.1 Question 1
Maîtriser les fonctions
Formation expertise
On vous propose une analyse de la base de données revenus_dep_2014. Malheureusement, une erreur survient lorsque vous tentez d’exécuter. Quelle est cette erreur et pourquoi survient-elle ?
# Nettoyage de l'environnement hors chemins ---------------rm(list =setdiff(ls(), ls(pattern ="^PATH")))ls()# Chargement des données ---------------load(file =paste(PATH_FINAL, "analyses_revenus_dep.RData", sep ="/"))# Paramétrage --------------------------SEUIL_PAUVRETE<-20# Analyses -----------------------------trouver_departements_pauvres<-function(data){departements_pauvres<-data%>%filter(TP6014>SEUIL_PAUVRETE)%>%select(LIBGEO)%>%pull()return(departements_pauvres)}trouver_departements_pauvres(revenus_dep_2014)print(paste("Les départements dont le taux de pauvreté dépasse", SEUIL_PAUVRETE, "sont :", paste(departements_pauvres, collapse =", ")))
4.2 Correction 1
Maîtriser les fonctions
Formation expertise
Le problème est lié aux variables locales et globales. En effet, au sein de la fonction trouver_departements_pauvres, la variable departements_pauvres est créee. C’est une variable locale qui n’a pas de portée en dehors de la fonction. Ainsi, lorsque l’on tente d’appeler cette variable en dehors de la fonction, une erreur survient.
Pour résoudre ce problème, on peut faire en sorte d’enregistrer la variable locale au sein de l’environnement global en enregistrant le résultat de la fonction dans une variable globale. On écrirait alors le code de la manière suivante :
load(file =paste(PATH_FINAL, "analyses_revenus_dep.RData", sep ="/"))SEUIL_PAUVRETE<-20trouver_departements_pauvres<-function(data){departements_pauvres<-data%>%filter(TP6014>SEUIL_PAUVRETE)%>%select(LIBGEO)%>%pull()return(departements_pauvres)}departements_pauvres<-trouver_departements_pauvres(revenus_dep_2014)print(paste("Les départements dont le taux de pauvreté dépasse", SEUIL_PAUVRETE, "sont :", paste(departements_pauvres, collapse =", ")))
[1] "Les départements dont le taux de pauvreté dépasse 20 sont : Aude, Haute-Corse, Gard, Pas-de-Calais, Pyrénées-Orientales, Vaucluse, Seine-Saint-Denis, Martinique, La Réunion"
4.4 Question 2
Maîtriser les fonctions
Formation expertise
Créer une fonction calculer_stat prenant en argument un dataframe et calculant, pour les variables numériques, les statistiques élémentaires renseignées en arguments. Par exemple, on pourra tout aussi bien lancer les commandes calculer_stat(revenus_dep_2014, min, max, median) que calculer_stat(revenus_dep_2014, sd, var, min)
4.5 Correction 2
Maîtriser les fonctions
Formation expertise
calculer_stat<-function(df, ...){# Lister les fonctions statistiques passées en argumentsfonctions<-list(...)resultats<-df%>%summarise(across(where(is.numeric), fonctions))%>%pivot_longer( cols =everything(), names_to ="variable", values_to ="valeur")return(resultats)}calculer_stat(revenus_dep_2014, min, max, mean)
L’objectif de cette séquence est de présenter les différentes dimensions à considérer pour évaluer la qualité d’un code. Il permettra ainsi de fournir des bonnes pratiques à appliquer lors de la production de code, ce qui permet de faciliter la prise en main, la maintenance et la réutilisation du code produit.
6.2 Mise en place
Reconnaître la qualité d’un code
Formation expertise
On se place dans le projet “R_Expertise” créé au début de la séquence 1. On initialise un script de travail :
Un code de qualité est un code qui présente les caractéristiques suivantes :
Justesse : le code fait ce que l’on veut
Lisibilité : il est compréhensible
Robustesse : il est capable de fonctionner avec des conditions variables (par exemple les données) et anticipe au maximum les cas nouveaux
Efficacité : les temps d’exécution et l’utilisation de la mémoire sont optimisés, les solutions choisies sont efficaces d’un point de vue complexité
Bien coder, c’est faire un compromis judicieux entre ces différents objectifs. Il est donc crucial de bien connaître le contexte (de combien de temps on dispose, à quoi va servir le code, sera-t-il réutilisé, etc.) afin de produire le code avec le degré de qualité le plus adapté et le plus pertinent.
Produire un code de qualité permet de faciliter la maintenance et la réutilisation du code.
7.2 Question 1
Reconnaître la qualité d’un code
Formation expertise
Classer les situations suivantes en fonction du curseur de compromis :
Situation 1 : Votre code s’exécute en 20s et pourrait être optimisé mais il n’est utilisé qu’un petit nombre de fois.
Situation 2 : En 20 minutes, vous produisez un code juste mais avec un temps d’exécution assez long. Ce code sera utilisé à de multiples reprises.
Situation 3 : En 1 jour, vous produisez un code juste qui s’exécute rapidement, mais après l’avoir utilisé, vous recevez une erreur Error: Cannot Allocate Vector of Size 12 Gb.
L’objectif de cette question est de mettre en lumière l’arbitrage entre coût de production et usage : quels efforts devrait-on mettre dans l’amélioration de la qualité d’un code ?
7.3 Justesse
Reconnaître la qualité d’un code
Formation expertise
L’évaluation de la qualité d’un code commence par la réalisation de tests de cohérence notamment sur des situations clés où des scénarii divers sont susceptibles d’arriver (exemple : assignation conditionnelle d’une valeur à une variable, etc.), et de vérifier ses résultats (voir Formation Consolidation - Séquence 1 : Devenir autonome en R).
Note : il faudra toutefois faire attention à bien se limiter dans le nombre de tests car ils peuvent rapidement devenir chronophages. Il convient donc de choisir les tests à réaliser de façon pertinente.
7.4 Question 2
Reconnaître la qualité d’un code
Formation expertise
On utilise la base naissances1019 disponible via doremifasol. Afin, de ne garder que les codes géographiques (CODGEO) correspondant à l’Ain (département numéro 1, soit les codes géographiques commençant par “01”), le code suivant a été produit. Vérifier la justesse de ce code. Dans le cas où le code n’est pas juste, proposer une meilleure version.
7.5 Correction 2
Reconnaître la qualité d’un code
Formation expertise
# Import des donnéesnaissances1019<-telechargerDonnees("NAISSANCES_COM_1019", telDir =PATH_INPUT)
# Sélection des lignes avec un CODGEO strictement inférieur à 2000naissances_CODGEO_moins_2000<-naissances1019%>%filter(CODGEO<2000)set.seed(123)naissances_CODGEO_moins_2000%>%sample_n(size =10)
En observant le dataframe resultant, on se rend compte que le code n’est pas juste puisque nous souhaitions avoir les lignes avec des CODGEO strictement inférieurs à 2000 et que les codes retournés sont compris entre “01001” (1001) et “19289” (19289). Le problème vient du type de la colonne CODGEO. En effet, cette colonne contient des nombres stockés sous forme de chaînes de caractères et pour comparer la valeur de CODGEO à 2000, R va implicitement convertir le nombre 2000 en “2000”. Il s’agit en fait d’une comparaison entre chaînes de caractères ; “19289” est inférieur à “2000” dans l’ordre lexixographique.
7.6 Correction 2
Reconnaître la qualité d’un code
Formation expertise
Pour corriger le code, on peut remplacer 2000 par “02000” dans le critère de comparaison :
# Sélection des lignes avec un CODGEO strictement inférieur à 2000naissances_CODGEO_moins_2000_corr<-naissances1019%>%filter(CODGEO<"02000")naissances_CODGEO_moins_2000_corr%>%sample_n(size =10)
Cette fois-ci, le résultat correspond à ce qui était attendu.
Note : Il aurait également été possible de convertir la colonne CODGEO en format numérique pour la comparaison s’il n’y avait pas eu des codes alphanumériques (ex : les codes en 2A et 2B pour la Corse). Une meilleure approche serait d’utiliser une fonction comme substr ou des expressions régulières (qui seront abordées lors de laséquence 5) pour vérifier que les deux premiers caractères de CODGEO valent “01”.
7.7 assert
Reconnaître la qualité d’un code
Formation expertise
La fonction testit::assert permet de vérifier une condition. L’utilisation est la suivante :
Souvent on connait à l’avance des bornes sur l’amplitude de certaines variables. Par exemple, si une variable désigne le nombre d’habitants dans un pays, a priori les valeurs devraient se situer entre 0 et 8 milliards (~ la population mondiale). On peut donc vérifier le minimum ou le maximum de ces variables afin de s’assurer de leur qualité et de la compréhension de leur signification ; ces statistiques peuvent donner une idée des ordres de grandeur et par exemple révéler une unité spécifique (valeur en milliers, millions etc.).
De même on peut vérifier d’autres statistiques comme la moyenne.
7.9 Question 3
Reconnaître la qualité d’un code
Formation expertise
Vérifier dans le dataframe naissances1019 que le nombre de naissances n’est jamais négatif et que le nombre de naissances annuel sur toute la France se situe chaque année entre 100000 et 10 millions.
7.10 Correction 3
Reconnaître la qualité d’un code
Formation expertise
testit::assert("Il y a des nombres de naissances négatifs",{mins<-naissances1019%>%summarise(across(where(is.numeric), \(x)min(x, na.rm =TRUE)))%>%min()mins>=0})testit::assert("Le nombre annuel de naissances n'est pas bon",{sums<-naissances1019%>%summarise(across(where(is.numeric), \(x)sum(x, na.rm =TRUE)))%>%min()(sums>1e5)(sums<1e7)})
Il n’y a pas eu d’erreur : les tests sont tous validés.
7.11 Autres fonctions de test
Reconnaître la qualité d’un code
Formation expertise
Il existe également d’autres fonctions permettant de tester des conditions. Il y a notamment identical, qui permet de déterminer si deux objets sont identiques (notion qui diffère de l’égalité) :
La fonction all.equal permet quant a elle permet de vérifier si tous les éléments sont égaux. Une certaine marge d’erreur (ajustable avec l’argument tolerance) est acceptée pour les comparaisons numériques ce qui permet de négliger les approximations numériques :
Vérifier que la variable CODGEO est de classe character.
7.13 Correction 4
Reconnaître la qualité d’un code
Formation expertise
testit::assert(# Le message en cas d'erreur est optionnelclass(naissances1019$CODGEO)=="character")
8 Lisibilité
8.1 Définition
Reconnaître la qualité d’un code
Formation expertise
Un code lisible est un code qui est compréhensible à la lecture et respecte les bonnes pratiques d’écriture (celles-ci sont écrites dans la séquence 2 de la formation Consolidation), ce qui signifie qu’il :
respecte les conventions / bonnes pratiques du langage (indentation, retours à la ligne, espacement des lignes de code, noms de variables qui ont du sens etc.)
est bien structuré en sections (notamment en utilisant les titres au format “# Titre 1 ————————————-”)
est commenté à bon escient et de manière détaillée (pour les fonctions, décrire l’input, l’output et idéalement le traitement réalisé par la fonction)
Note
On évitera toutefois de commenter toutes les lignes, en particulier celles qui sont explicites par elles-mêmes (exemple : renommage d’une variable, etc.).
8.2 Définition
Reconnaître la qualité d’un code
Formation expertise
La lisibilité du code est très importante car au-delà de permettre à un tiers de comprendre ce qui est fait, elle permet de garantir d’autres points d’évaluation de la qualité d’un code. En effet, un code qui est lisible est plus facile à maintenir et à réaliser / adapter.
UtilitR présente des éléments sur la Qualité d’un code avec notamment l’utilisation des packages :
lintr pour obtenir des diagnostics de qualité du code
styler pour reprendre automatiquement le formatting d’un script
8.3 Question 5
Reconnaître la qualité d’un code
Formation expertise
Relever les éléments qui rendent le code suivant peu lisible.
le but de l’extrait de code n’est pas explicité / n’est pas évident
il n’y a pas de commentaires au fur et à mesure
les noms de dataframes et de variables ne sont pas clairs
le code ne respire pas (absence de passage à la ligne, d’espaces…)
par ailleurs la fonction mutate_at est superseded (c’est à dire qu’elle n’est pas recommandée)
8.5 Correction 5
Reconnaître la qualité d’un code
Formation expertise
À l’inverse, l’exemple de code suivant est plus lisible :
library(ggplot2)## On souhaite savoir combien de communes on eu plus de 10 naissances en 2010 et en 2011# Variables à gardervar_naissances_20102011<-c("CODGEO", "NAISD10", "NAISD11")# Construction de la base de travailnaissances_plus_10_20102011<-naissances1019%>%select(all_of(var_naissances_20102011))%>%# si une variable est numérique, on regarde si on a eu plus de 10 naissancesmutate(across(where(is.numeric), function(x)(x>10)))%>%tidyr::pivot_longer(cols =c("NAISD10", "NAISD11"), names_to ="annee_naissance", values_to ="plus_de_10")%>%# on fait l'hypothèse que les NA sont inférieurs à 10tidyr::replace_na(list(plus_de_10 =FALSE))# Représentations graphiquesnaissances_plus_10_20102011%>%ggplot(aes(x =plus_de_10))+geom_histogram(stat ="count")+facet_grid(cols =vars(annee_naissance))
8.6 Documenter une fonction
Reconnaître la qualité d’un code
Formation expertise
Il est important de bien documenter les fonctions afin d’aider la compréhension du code. La documentation d’une fonction s’appuie sur la syntaxe de roxygen2 (qu’on développera lors de la séquence 6 - Les bases d’un package). Le raccourcis CTRL+ALT+MAJ+R depuis le corps d’une fonction permet de générer automatiquement les tags roxygen :
# Les lignes commençant par #' ont été générés automatiquement par le raccourcis#' Title#'#' @param x#' @param y#'#' @return#' @export#'#' @examplesadd<-function(x, y){x+y}
9 Robustesse
9.1 Introduction
Reconnaître la qualité d’un code
Formation expertise
Un code est robuste lorsqu’il est suffisamment générique pour être adapté. Autrement dit, il n’utilise pas de spécificités qui sont susceptibles de changer et pourra donc être facilement utilisé dans un contexte similaire sans subir trop de modifications, permettant ainsi de gagner du temps.
La robustesse d’un code est également liée à sa tolérance à des changements dans le cadre où il a été écrit, c’est-à-dire qu’il ne nécessite pas ou peu de modifications si d’autres changements ont été apportés ailleurs dans le code / sur les données utilisées
Afin d’avoir le code le plus robuste possible, il est important :
d’éviter les répétitions
d’éviter de hard-coder
d’anticiper les potentiels cas problématiques
9.2 Eviter les répétitions
Reconnaître la qualité d’un code
Formation expertise
Un principe général à respecter est le suivant : si une partie du code est répétée plusieurs fois, c’est qu’il est probablement pertinent de créer une fonction et de l’appeler plusieurs fois avec les bons paramètres. Eviter les répétitions présente plusieurs avantages :
Cela minimise le risque d’erreur
Cela rend le code plus lisible
Cela permet de coder plus efficacement
9.3 Eviter les répétitions
Reconnaître la qualité d’un code
Formation expertise
On suppose pour illustrer ce principe qu’on souhaite produire trois graphiques sur le même modèle que celui produit précédemment, mais pour les années 2016-2017, 2017-2018 et 2018-2019. On procède comme suit :
library(ggplot2)## On souhaite savoir combien de communes on eu plus de 10 naissances en 2016 et en 2017# Variables à gardervar_naissances_20162017<-c("CODGEO", "NAISD16", "NAISD17")# Construction de la base de travailnaissances_plus_10_20162017<-naissances1019%>%select(all_of(var_naissances_20162017))%>%# si une variable est numérique, on regarde si on a eu plus de 10 naissancesmutate(across(where(is.numeric), function(x)(x>10)))%>%tidyr::pivot_longer(cols =c("NAISD16", "NAISD17"), names_to ="annee_naissance", values_to ="plus_de_10")%>%# on fait l'hypothèse que les NA sont inférieurs à 10tidyr::replace_na(list(plus_de_10 =FALSE))# Représentations graphiquesnaissances_plus_10_20162017%>%ggplot(aes(x =plus_de_10))+geom_histogram(stat ="count")+facet_grid(cols=var(annee_naissance))
9.4 Eviter les répétitions
Reconnaître la qualité d’un code
Formation expertise
## On souhaite savoir combien de communes on eu plus de 10 naissances en 2017 et en 2018# Variables à gardervar_naissances_20172018<-c("CODGEO", "NAISD17", "NAISD18")# Construction de la base de travailnaissances_plus_10_20172018<-naissances1019%>%select(all_of(var_naissances_20172018))%>%# si une variable est numérique, on regarde si on a eu plus de 10 naissancesmutate(across(where(is.numeric), function(x)(x>10)))%>%tidyr::pivot_longer(cols =c("NAISD17", "NAISD18"), names_to ="annee_naissance", values_to ="plus_de_10")%>%# on fait l'hypothèse que les NA sont inférieurs à 10tidyr::replace_na(list(plus_de_10 =FALSE))# Représentations graphiquesnaissances_plus_10_20172018%>%ggplot(aes(x =plus_de_10))+geom_histogram(stat ="count")+facet_grid(cols =var(annee_naissance))
9.5 Eviter les répétitions
Reconnaître la qualité d’un code
Formation expertise
## On souhaite savoir combien de communes on eu plus de 10 naissances en 2018 et en 2019# Variables à gardervar_naissances_20182019<-c("CODGEO", "NAISD18", "NAISD19")# Construction de la base de travailnaissances_plus_10_20182019<-naissances1019%>%select(all_of(var_naissances_20182019))%>%# si une variable est numérique, on regarde si on a eu plus de 10 naissancesmutate(across(where(is.numeric), function(x)(x>10)))%>%tidyr::pivot_longer(cols =c("NAISD18", "NAISD19"), names_to ="annee_naissance", values_to ="plus_de_10")%>%# on fait l'hypothèse que les NA sont inférieurs à 10tidyr::replace_na(list(plus_de_10 =FALSE))# Représentations graphiquesnaissances_plus_10_20182019%>%ggplot(aes(x =plus_de_10))+geom_histogram(stat ="count")+facet_grid(cols =var(annee_naissance))
9.6 Question 6
Reconnaître la qualité d’un code
Formation expertise
Proposer une fonction permettant d’éviter les répétitions précédentes.
9.7 Correction 6
Reconnaître la qualité d’un code
Formation expertise
## Fonction permettant de visualiser le nombre de communes ayant eu plus de 10 naissances sur deux années# Input : noms des deux variables (années) à prendre en compte pour le graphique# Output : graphique avec les nombres de communes ayant eu plus de 10 naissances sur les deux annéesplot_naissances<-function(variable1, variable2){# Construction de la base de travailnaissances_plus_10<-naissances1019%>%select(all_of(c("CODGEO", {{variable1}}, {{variable2}})))%>%# si une variable est numérique, on regarde si on a eu plus de 10 naissancesmutate(across(where(is.numeric), function(x)(x>10)))%>%tidyr::pivot_longer(cols =c({{variable1}}, {{variable2}}), names_to ="annee_naissance", values_to ="plus_de_10")%>%# on fait l'hypothèse que les NA sont inférieurs à 10tidyr::replace_na(list(plus_de_10 =FALSE))plot<-naissances_plus_10%>%ggplot(aes(x =plus_de_10))+geom_histogram(stat ="count")+facet_grid(cols =vars(annee_naissance))return(plot)}# Exemple pour 2018-2019plot_naissances("NAISD18", "NAISD19")
9.8 Eviter de hard-coder
Reconnaître la qualité d’un code
Formation expertise
Dans la mesure du possible, il est important d’éviter de hard-coder, c’est-à-dire de coder en utilisant des valeurs “en dur” qui ne seraient pas robustes au moindre changement (ex : mise à jour du fichier d’entrée).
L’exemple (trivial) suivant illustre cette mauvaise pratique. On utilise pour l’exemple les 10 premières observations du dataframe des naissances, et on suppose qu’on souhaite garder les observations pour lesquelles le nombre de naissances en 2019 vaut au moins 10.
Voici un mauvais exemple :
# On filtre les 10 premières observations du dataframe pour l'exemplenaissances1019_entete<-naissances1019%>%filter(row_number()<=10)naissances1019_entete
# Après observation du dataframe, on rentre les valeurs à filtrer en durnaissances1019_entete%>%filter(row_number()%in%c(3, 4, 6, 9))
Nous avons vu dans la formation Consolidation, Séquence 6 : Projet statistique - Modulariser les analyses, comment utiliser les boucles for et les boucles while. Dans le cadre de l’utilisation de boucles, il est important d’anticiper les potentiels cas qui pourraient poser problème et faire “casser” une boucle. Les commandes break et next répondent à ce besoin.
9.11break
Reconnaître la qualité d’un code
Formation expertise
La commande break s’utilise à l’intérieur d’une boucle (for, while ou repeat) afin de signifier que la boucle doit être arrêtée. Par exemple, si on souhaite afficher tous les éléments d’une liste jusqu’à rencontrer un élément spécifique, on peut écrire :
Lorsque la boucle a rencontré l’élément “Python”, la commande break a bien permis de stopper la boucle.
9.12next
Reconnaître la qualité d’un code
Formation expertise
La commande next s’utilise également à l’intérieur d’une boucle mais contrairement à la commande break, celle-ci ne force pas l’arrêt de la boucle mais permet d’ignorer une itération. Ainsi, si on souhaite par exemple afficher tous les nombres pairs entre 0 et 10, on peut écrire :
On souhaite identifier les 10 communes (hors de Paris) ayant eu le plus de naissances sur l’ensemble de la période 2010-2019. On propose le code suivant. Relever les éléments qui rendent le rendent peu robuste et proposer un meilleur code en tenant compte de ces éléments.
# Objectif du code : trouver les 10 communes (hors de Paris)# avec le plus de naissances. Afficher dans un tableauvilles_nb_naissances<-data.frame( CODGEO =NULL, NB_NAIS =NULL)paris<-c("75101", "75102", "75103", "75104", "75105","75106", "75107", "75108", "75109", "75110","75111", "75112", "75113", "75114", "75115","75116", "75117", "75118", "75119", "75120","75056")for(idinnaissances1019$CODGEO){if(id%in%paris){next}else{CODGEO<-idNB_NAIS<-naissances1019$NAISD10[naissances1019$CODGEO==id]+naissances1019$NAISD11[naissances1019$CODGEO==id]+naissances1019$NAISD12[naissances1019$CODGEO==id]+naissances1019$NAISD13[naissances1019$CODGEO==id]+naissances1019$NAISD14[naissances1019$CODGEO==id]+naissances1019$NAISD15[naissances1019$CODGEO==id]+naissances1019$NAISD16[naissances1019$CODGEO==id]+naissances1019$NAISD17[naissances1019$CODGEO==id]+naissances1019$NAISD18[naissances1019$CODGEO==id]+naissances1019$NAISD19[naissances1019$CODGEO==id]villes_nb_naissances<-villes_nb_naissances%>%rbind(c(CODGEO, NB_NAIS))}}colnames(villes_nb_naissances)<-c("CODGEO", "NB_NAIS")villes_triees<-villes_nb_naissances%>%mutate(NB_NAIS =as.numeric(NB_NAIS))%>%arrange(desc(NB_NAIS))villes_top_10<-villes_triees%>%slice_head(n =10)villes_top_10
9.14 Correction 7
Reconnaître la qualité d’un code
Formation expertise
Le code précédent fonctionne mais n’est pas robuste :
Les observations correspondant à Paris sont renseignées en dur, ce qui est moins robuste qu’une méthode consistant à repérer Paris par les deux premiers numéros du code géographique valant 75
Le code présente de nombreuses répétitions (sur les variables)
Par ailleurs, cela contribue à rendre le code peu lisible et inefficace.
9.15 Correction 7
Reconnaître la qualité d’un code
Formation expertise
Le code suivant constitue une meilleure solution :
L’utilisation de deux principales ressources permet de juger de l’efficacité d’un code :
Le temps d’exécution du code
La mémoire utilisée
Les fonctions suivantes existent pour faciliter l’optimisation du temps d’exécution d’un code :
La fonction Sys.time pour mesurer le temps d’exécution associé à un code donné
La fonction mark() disponible à travers le package bench pour comparer les temps d’exécution de plusieurs codes réalisant la même tâche
Par ailleurs, deux méthodes ont été présentées pour optimiser l’utilisation des ressources : le calcul parallélisé et le calcul distribué.
10.2 La complexité algorithmique
Reconnaître la qualité d’un code
Formation expertise
La complexité d’un algorithme est une notion relative à la quantité de ressources informatiques utilisées par l’algorithme.
La complexité temporelle évalue l’efficacité d’un algorithme en se basant sur le taux de croissance du temps d’exécution lorsque la taille de l’entrée augmente. Elle fournit une estimation du temps nécessaire à un algorithme pour s’exécuter
La complexité spatiale évalue l’efficacité d’un algorithme en analysant la quantité de mémoire dont il a besoin pour stocker les données et exécuter les opérations
La prise en compte de l’efficacité algorithmique est cruciale lors de la programmation, car elle a un impact direct sur les performances. En concevant et en mettant en œuvre des algorithmes moins complexes en termes de temps et d’espace, les développeurs peuvent améliorer la vitesse et la réactivité de leurs applications, minimiser le gaspillage des ressources et s’adapter à des entrées de plus grande taille.
10.3 Pour en savoir plus : mesurer la complexité d’un algorithme
Reconnaître la qualité d’un code
Formation expertise
Comme expliqué plus haut, la complexité d’un algorithme est une mesure de la quantité de ressources (temps et espace) qu’il nécessite pour s’exécuter en fonction de la taille de l’entrée. Elle est souvent exprimée avec la notation (O(n)) (lu “grand O de n”), où n représente la taille de l’entrée. La notation (O(n)) indique que la complexité de l’algorithme est linéaire, ce qui signifie que le temps d’exécution (ou l’utilisation de la mémoire) croît de manière proportionnelle à la taille de l’entrée.
Par exemple, considérons un algorithme qui parcourt une liste d’éléments pour les afficher. Si la liste contient n éléments, cet algorithme aura une complexité (O(n)) car il devra itérer sur chaque élément une fois pour les afficher. Ainsi, si la taille de la liste double, le temps d’exécution (ou l’utilisation de la mémoire) doublera également.
10.4 Pour en savoir plus : mesurer la complexité d’un algorithme
Reconnaître la qualité d’un code
Formation expertise
En plus de la complexité linéaire, il existe d’autres familles de complexité. Par exemple, une complexité polynomiale est représentée par la notation (O(nk)), où k est un entier positif. Cela signifie que la complexité de l’algorithme croît de manière polynomiale avec la taille de l’entrée. Par exemple, un algorithme qui effectue toutes les paires possibles de deux éléments dans une liste de n éléments aura une complexité (O(n2)). Si la taille de la liste double, le temps d’exécution (ou l’utilisation de la mémoire) sera multiplié par quatre.
Enfin, une complexité exponentielle est représentée par la notation (O(kn)), où k est une constante supérieure à 1. Cela signifie que la complexité de l’algorithme croît de manière exponentielle avec la taille de l’entrée, ce qui peut rendre l’algorithme très coûteux pour les entrées de grande taille. Par exemple, un algorithme qui génère tous les sous-ensembles d’un ensemble de n éléments aura une complexité (O(2n)). Si la taille de l’ensemble double, le temps d’exécution (ou l’utilisation de la mémoire) sera multiplié par deux à la puissance n (à savoir, mis au carré).
11 Quiz
11.1 Question 1
Reconnaître la qualité d’un code
Formation expertise
Quel est l’intérêt d’assurer la production d’un code qualité ?
A) Cela permet de faciliter sa réutilisation et sa maintenance
B) Cela permet de gagner en temps d’exécution
C) Cela permet d’assurer qu’il produira toujours le résultat attendu
11.2 Correction 1
Reconnaître la qualité d’un code
Formation expertise
Les réponses A), B) et C) sont correctes.
11.3 Question 2
Reconnaître la qualité d’un code
Formation expertise
A quoi servent les tests de cohérence ?
A) d’attester de l’efficacité du code
B) d’attester de la lisibilité du code
C) d’attester de la justesse du code
11.4 Correction 2
Reconnaître la qualité d’un code
Formation expertise
La réponse correcte est la réponse :
C) d’attester de la justesse du code. NB : les tests de cohérence peuvent aussi s’avérer utiles pour s’assurer de la maintenabilité du code.
On souhaite connaître les communes ayant eu au moins 100 naissances dans les départements de l’Ain (01), de l’Aisne (02) et de l’Allier (03) entre 2010 et 2015. On propose une première version du code :
# Nb naissances Ainnaissances_ain<-c()ain<-naissances1019$CODGEO[startsWith(naissances1019$CODGEO, "01")]for(communeinain){total_nais<-rowSums(naissances1019[2:7], na.rm =TRUE)[naissances1019$CODGEO==commune]if(total_nais>=100){naissances_ain<-c(naissances_ain, commune)}}# Nb naissances Aisnenaissances_aisne<-c()aisne<-naissances1019$CODGEO[startsWith(naissances1019$CODGEO, "02")]for(communeinaisne){total_nais<-rowSums(naissances1019[2:7], na.rm =TRUE)[naissances1019$CODGEO==commune]if(total_nais>=100){naissances_aisne<-c(naissances_aisne, commune)}}# Nb naissances Alliernaissances_allier<-c()allier<-naissances1019$CODGEO[startsWith(naissances1019$CODGEO, "03")]for(communeinallier){total_nais<-rowSums(naissances1019[2:7], na.rm =TRUE)[naissances1019$CODGEO==commune]if(total_nais>=100){naissances_allier<-c(naissances_allier, commune)}}
Qu’observez-vous ? Quelles améliorations pourraient être apportées ?
12.2 Correction 1
Reconnaître la qualité d’un code
Formation expertise
On observe un copier-coller sur une boucle. On peut décider de remplacer cette boucle par une fonction.
On observe également du hard-coding, avec la somme des colonnes 2 à 7, ce qui n’est pas robuste.
Une proposition d’amélioration pourrait être :
# Définition d'une fonction# Objectif : récupérer les communes d'un département pour lesquelles# la somme des naissances entre 2010 et 2015 a dépassé un certain seuil# Paramètres : dpt = département d'intérêt, seuil = seuil minimal des naissances voulu (défaut seuil à 100)# Sortie : vecteur de codes communenaissance_fct<-function(dpt, seuil=100){wk_naissances<-naissances1019%>%# on filtre sur le départementfilter(startsWith(CODGEO, dpt))%>%# on somme sur 2010-1015mutate(total_nais =rowSums(across(ends_with(c("10", "11", "12", "13", "14", "15"))), na.rm =TRUE))%>%filter(total_nais>=seuil)res<-wk_naissances$CODGEOreturn(res)}# On l'applique pour nos 3 départements d'intérêt# AINnaissances_ain<-naissance_fct("01")# AISNEnaissances_aisne<-naissance_fct("02")# ALLIERnaissances_allier<-naissance_fct("03")
12.3 Question 2
Reconnaître la qualité d’un code
Formation expertise
Evaluer la qualité du code ci-dessous et le cas échéant, relever les éléments qui diminuent la qualité pour chacun des aspects (justesse, robustesse, …).
Les valeurs de rowSums ne sont pas correctes car il y a des valeurs manquantes qui sont prises en compte
Efficacité :
Le code s’exécute rapidement, mais la création d’un dataframe intermédiaire (new_data) est évitable, on peut le rendre plus efficace
Lisibilité :
Il n’y a aucun commentaire
Les noms de variables / colonnes ne sont pas parlants
Robustesse :
Certaines lignes sont hard-codées
Le code a peu de tolérance au changement (test est restreint aux colonnes 1 à 12, le code ne supporterait pas une permutation des colonnes)
12.5 Correction 2
Reconnaître la qualité d’un code
Formation expertise
# ajout d'une colonne total par commune sur toutes les annéesnb_naissance_total_par_departement<-naissances1019%>%mutate( total =rowSums(.[-1]), dpt =substring(naissances1019$CODGEO, 1, 2))%>%group_by(dpt)%>%# on regroupe par département (les 2 premiers caractères)summarise(total_naissances =sum(total, na.rm =TRUE))# agrégation du résultat du regroupement par une sommenb_naissance_total_par_departement
La séquence précédente a permis de présenter les dimensions à prendre en compte pour produire un code de qualité (justesse, lisibilité, robustesse et efficacité) et de fournir des premières bonnes pratiques à adopter. Cette séquence a pour but de fournir aux stagiaires des outils supplémentaires pour améliorer leur code.
Elle permet :
d’apprendre aux stagiaires à rendre leur code plus efficace à travers l’utilisation des formats de variables les plus adaptés, de la vectorisation, du garbage collector.
de présenter des fonctionnalités utiles permettant de faciliter la production d’un code juste et en particulier la résolution d’erreurs
d’apprendre à produire un code robuste lorsqu’il s’agit de manipuler des chaînes de caractères grâce au concept d’expressions régulières
15 Efficacité
15.1 Introduction
Améliorer son code
Formation expertise
L’objectif de cette section est de fournir plusieurs outils permettant de rendre un code plus efficace. Elle permettra de présenter des méthodes relativement simples à mettre en place comme le concept de garbage collection et l’utilisation de types de variables adaptés. Nous aborderons également la vectorisation qui une fois adoptée, permet de rendre son code considérablement plus efficace.
Tout au long de cette section, nous travaillerons sur la table revenus suivante :
15.2 Question 1
Améliorer son code
Formation expertise
En utilisant la fonction pryr::object_size, déterminer la taille de la table revenus en mémoire
En fonction du contexte, il peut être pertinent de convertir des variables dans un format différent afin d’optimiser l’utilisation des ressources. En particulier, il est recommandé d’utiliser lorsque c’est possible :
des booléens pour les variables binaires
des facteurs pour les variables catégorielles
Dans notre table, la colonne possede_permis représente une variable binaire indiquant si une personne possède un permis de conduire (oui ou non). Nous pouvons optimiser la mémoire en convertissant cette variable binaire en un format plus efficace, à savoir les booléens (variable TRUE/FALSE).
15.5 Question 2
Améliorer son code
Formation expertise
Convertir les éléments de la colonne possede_permis en booléens
La différence de mémoire utilisée est donc de 0,04 MB.
15.9 Question 4
Améliorer son code
Formation expertise
Existe-t-il d’autres colonnes qu’il est possible de transformer de la même manière ? Si oui, faire les changements adéquats et calculer le gain de mémoire.
La différence de mémoire utilisée encore égale à 0,04 MB.
15.11 Les facteurs
Les facteurs en R sont une représentation efficace des variables catégorielles, permettant d’optimiser le stockage et la manipulation de données discrètes. Lorsque nous travaillons avec des variables catégorielles, telles que les niveaux d’éducation, les régions géographiques, ou les classifications de produits, l’utilisation de chaînes de caractères peut entraîner une consommation excessive de mémoire. Les facteurs résolvent ce problème en attribuant un indice unique à chaque catégorie et en stockant les données sous forme d’entiers, ce qui réduit considérablement l’emprunte mémoire. En convertissant ces variables catégorielles en facteurs, non seulement nous économisons de l’espace, mais nous améliorons également l’efficacité des opérations statistiques et graphiques qui peuvent être effectuées sur ces données.
15.12 Question 5
Améliorer son code
Formation expertise
Quelles sont la/les variables de notre table que l’on pourrait transformer en facteurs ?
15.13 Correction 5
Améliorer son code
Formation expertise
La variable niveau_education est une variable catégorielle qu’il est possible de transformer en facteur.
15.14 Question 6
Améliorer son code
Formation expertise
Transformer la/les variables pertinentes en facteurs
15.15 Correction 6
Améliorer son code
Formation expertise
Pour transformer la variable niveau_education en facteur, on utilise la fonction as.factor
# Conversion en facteursrevenus<-revenus%>%mutate(niveau_education =as.factor(niveau_education))# Afficher les niveaux de facteurslevels(revenus$niveau_education)
[1] "Bac" "Bac +3" "Bac +5" "Brevet"
15.16 Question 7
Améliorer son code
Formation expertise
Calculer le gain de mémoire obtenu à l’aide de la transformation précédente
La différence de mémoire utilisée est donc égale à 0,04 MB.
15.18 A savoir : Utilisation de la mémoire par les vecteurs
Améliorer son code
Formation expertise
L’ajout d’éléments supplémentaires dans un vecteur de taille donnée (et donc l’augmentation de la taille du vecteur en question) génère beaucoup de mouvements en mémoire. En effet, à chaque ajout d’éléments supplémentaires dans le vecteur, R recrée un nouveau vecteur. Ainsi, si l’on manipule par exemple un vecteur auquel on ajoute des éléments de façon itérative, il est plus efficace en termes d’utilisation de mémoire d’initialiser ce vecteur avec sa taille finale (quitte à laisser des valeurs manquantes) et de modifier ses éléments.
15.19 Opérations sur les facteurs
Améliorer son code
Formation expertise
Le package forcats propose quelques fonctions permettant de transformer les facteurs, par exemple :
fct_reorder : Réordonne un facteur selon une autre variable
fct_infreq : Réordonne un facteur selon la fréquence des valeurs
Transformer la variable niveau_education en changeant le niveau le moins fréquent en “other”.
15.21 Correction 8
Améliorer son code
Formation expertise
revenus<-revenus%>%mutate(niveau_education =forcats::fct_lump(niveau_education, n =n_distinct(niveau_education)-1))revenus$niveau_education
[1] Bac +5 Other Bac +5 Other Bac +3 Bac +5 Brevet Bac +3 Brevet Bac +5
[11] Brevet Bac +3 Brevet Brevet Other Brevet Bac +5 Other Bac +3 Other
[21] Bac +3 Brevet Brevet Brevet Bac +3 Bac +3 Other Bac +3 Brevet Bac +5
[31] Bac +5 Brevet Brevet Bac +3 Bac +3 Bac +3 Other Other Bac +3 Bac +3
[41] Other Other Other Bac +5 Brevet Brevet Bac +3 Bac +3 Other Other
[51] Brevet Bac +5 Brevet Bac +3 Bac +5 Brevet Bac +3 Bac +3 Bac +3 Bac +5
[61] Other Bac +3 Bac +5 Bac +3 Bac +3 Bac +5 Bac +5 Bac +3 Bac +5 Bac +5
[71] Brevet Other Brevet Bac +5 Bac +3 Other Bac +5 Other Bac +3 Bac +3
[81] Other Bac +3 Brevet Other Bac +3 Bac +5 Other Other Bac +5 Brevet
[91] Bac +5 Brevet Brevet Bac +3 Brevet Other Bac +5 Bac +3 Bac +3 Other
[101] Brevet Other Bac +3 Brevet Other Bac +3 Brevet Brevet Other Brevet
[111] Bac +3 Other Other Other Brevet Bac +3 Brevet Bac +5 Bac +3 Other
[121] Other Brevet Bac +5 Other Bac +5 Bac +3 Brevet Bac +3 Brevet Bac +5
[131] Bac +3 Other Bac +5 Other Brevet Bac +3 Other Brevet Bac +3 Bac +3
[141] Other Other Brevet Other Bac +5 Brevet Bac +3 Other Brevet Other
[151] Other Bac +3 Bac +3 Bac +5 Bac +3 Brevet Bac +5 Bac +5 Other Bac +3
[161] Bac +3 Bac +3 Bac +3 Brevet Bac +3 Bac +3 Other Bac +5 Other Other
[171] Other Brevet Bac +3 Brevet Other Brevet Other Brevet Bac +3 Brevet
[181] Bac +3 Bac +5 Brevet Brevet Bac +3 Other Bac +5 Bac +3 Other Brevet
[191] Bac +3 Other Bac +5 Brevet Bac +5 Other Bac +3 Bac +5 Bac +5 Other
[201] Bac +5 Bac +5 Other Other Bac +5 Other Bac +3 Brevet Bac +3 Bac +5
[211] Bac +3 Bac +5 Bac +3 Bac +5 Bac +5 Bac +5 Other Other Other Brevet
[221] Bac +3 Other Other Bac +3 Bac +3 Brevet Bac +5 Brevet Bac +3 Other
[231] Bac +5 Other Brevet Other Other Brevet Brevet Bac +3 Bac +3 Brevet
[241] Other Bac +5 Bac +5 Other Brevet Bac +5 Bac +3 Bac +5 Brevet Other
[251] Bac +5 Other Bac +3 Brevet Bac +3 Other Bac +5 Bac +3 Other Brevet
[261] Brevet Other Bac +3 Bac +5 Bac +3 Bac +3 Bac +3 Brevet Bac +3 Brevet
[271] Bac +5 Bac +5 Brevet Brevet Bac +3 Bac +5 Bac +3 Other Bac +5 Bac +3
[281] Other Brevet Other Other Brevet Other Other Bac +3 Bac +5 Bac +3
[291] Bac +3 Bac +5 Brevet Bac +5 Other Bac +3 Other Other Brevet Bac +5
[301] Brevet Other Bac +3 Other Other Other Other Brevet Brevet Bac +3
[311] Other Brevet Brevet Bac +5 Bac +3 Brevet Brevet Bac +5 Bac +3 Brevet
[321] Bac +3 Other Bac +3 Brevet Brevet Brevet Bac +5 Other Other Brevet
[331] Other Other Bac +5 Other Bac +5 Other Bac +5 Bac +5 Other Bac +5
[341] Bac +3 Other Bac +3 Bac +5 Bac +5 Bac +3 Other Other Bac +5 Bac +5
[351] Bac +5 Bac +3 Bac +3 Brevet Bac +5 Bac +5 Bac +3 Bac +3 Bac +3 Bac +3
[361] Bac +3 Other Bac +3 Other Bac +5 Bac +3 Bac +3 Bac +3 Brevet Bac +5
[371] Brevet Bac +5 Brevet Bac +3 Other Bac +5 Brevet Brevet Brevet Bac +3
[381] Brevet Brevet Brevet Bac +3 Other Brevet Bac +5 Bac +5 Brevet Bac +5
[391] Bac +5 Other Brevet Bac +5 Bac +3 Other Other Other Bac +3 Bac +5
[401] Other Brevet Bac +5 Bac +5 Bac +3 Brevet Brevet Bac +3 Bac +3 Bac +5
[411] Brevet Other Bac +5 Other Bac +3 Bac +5 Bac +5 Other Other Bac +3
[421] Other Bac +5 Bac +3 Other Bac +3 Brevet Brevet Bac +5 Other Brevet
[431] Other Brevet Bac +3 Other Bac +3 Brevet Brevet Brevet Bac +3 Brevet
[441] Other Bac +3 Bac +3 Other Brevet Other Brevet Bac +5 Bac +3 Brevet
[451] Bac +5 Brevet Brevet Bac +5 Brevet Bac +5 Bac +3 Other Other Other
[461] Bac +3 Bac +5 Brevet Other Brevet Other Brevet Other Other Bac +5
[471] Brevet Brevet Bac +5 Bac +3 Bac +3 Other Other Bac +3 Brevet Brevet
[481] Bac +5 Bac +3 Bac +3 Brevet Bac +3 Brevet Other Other Bac +3 Other
[491] Other Bac +5 Brevet Brevet Bac +5 Bac +5 Bac +5 Bac +3 Bac +5 Other
[501] Bac +5 Brevet Bac +3 Other Bac +3 Bac +5 Bac +5 Bac +5 Bac +5 Bac +3
[511] Brevet Other Bac +3 Brevet Brevet Bac +3 Brevet Bac +3 Bac +5 Bac +3
[521] Bac +3 Other Bac +3 Other Other Brevet Other Bac +3 Bac +5 Bac +5
[531] Other Bac +5 Other Brevet Bac +3 Bac +3 Brevet Other Other Bac +3
[541] Other Bac +3 Bac +5 Bac +5 Other Brevet Other Brevet Other Brevet
[551] Other Other Bac +3 Bac +5 Bac +5 Other Bac +5 Bac +5 Bac +5 Other
[561] Brevet Bac +3 Bac +3 Bac +3 Brevet Bac +5 Brevet Bac +5 Bac +3 Bac +5
[571] Bac +3 Brevet Bac +3 Bac +3 Other Bac +3 Bac +3 Other Brevet Bac +5
[581] Bac +5 Other Bac +5 Other Bac +5 Other Bac +5 Other Bac +5 Brevet
[591] Bac +3 Bac +5 Other Other Other Other Bac +5 Bac +5 Bac +3 Brevet
[601] Brevet Brevet Bac +5 Bac +3 Bac +3 Bac +5 Other Other Other Bac +3
[611] Brevet Bac +5 Brevet Bac +3 Bac +3 Other Brevet Bac +3 Other Bac +5
[621] Other Bac +5 Other Other Bac +3 Bac +5 Bac +3 Bac +5 Bac +3 Brevet
[631] Bac +5 Bac +5 Brevet Other Bac +3 Bac +5 Other Other Bac +5 Bac +5
[641] Other Bac +3 Bac +5 Other Bac +3 Bac +3 Other Brevet Brevet Bac +5
[651] Brevet Bac +3 Bac +3 Other Bac +3 Bac +3 Bac +5 Bac +5 Brevet Brevet
[661] Bac +5 Other Other Bac +3 Other Bac +5 Brevet Bac +5 Other Brevet
[671] Bac +3 Bac +5 Brevet Brevet Bac +5 Other Other Brevet Other Bac +3
[681] Bac +5 Bac +3 Brevet Brevet Bac +3 Bac +3 Bac +3 Bac +3 Bac +3 Bac +3
[691] Other Bac +3 Other Brevet Brevet Brevet Bac +3 Other Other Brevet
[701] Bac +3 Brevet Bac +3 Bac +5 Other Bac +5 Brevet Other Bac +3 Other
[711] Bac +3 Other Bac +5 Bac +5 Brevet Brevet Brevet Bac +5 Bac +3 Other
[721] Bac +3 Bac +3 Bac +5 Bac +5 Other Bac +3 Bac +3 Bac +5 Bac +5 Bac +3
[731] Bac +5 Other Other Brevet Bac +3 Brevet Bac +5 Brevet Other Other
[741] Bac +3 Bac +3 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Bac +3 Brevet Other
[751] Brevet Bac +3 Brevet Bac +3 Bac +3 Brevet Bac +5 Bac +5 Bac +5 Bac +5
[761] Bac +5 Bac +3 Other Brevet Bac +5 Other Bac +3 Bac +5 Bac +3 Other
[771] Brevet Bac +3 Other Bac +3 Other Other Bac +5 Bac +5 Bac +5 Bac +3
[781] Bac +3 Bac +5 Bac +3 Bac +5 Bac +3 Bac +3 Other Bac +5 Bac +5 Other
[791] Other Brevet Brevet Other Bac +3 Other Other Bac +3 Bac +3 Bac +3
[801] Other Other Bac +5 Brevet Bac +3 Other Brevet Bac +5 Bac +3 Bac +5
[811] Brevet Other Other Other Bac +5 Bac +5 Bac +5 Other Other Brevet
[821] Brevet Bac +5 Brevet Other Brevet Other Brevet Bac +5 Bac +3 Other
[831] Bac +5 Brevet Other Bac +3 Other Other Bac +3 Bac +3 Bac +3 Bac +5
[841] Bac +3 Other Brevet Other Bac +3 Other Brevet Other Bac +5 Bac +5
[851] Other Bac +5 Bac +5 Bac +3 Bac +3 Other Other Bac +5 Brevet Other
[861] Brevet Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +3 Other Other Other
[871] Bac +3 Brevet Other Bac +3 Other Brevet Bac +3 Brevet Other Bac +5
[881] Bac +5 Brevet Bac +5 Bac +5 Brevet Bac +5 Bac +3 Brevet Other Brevet
[891] Brevet Brevet Bac +5 Bac +5 Brevet Bac +3 Bac +3 Brevet Bac +5 Bac +5
[901] Other Brevet Bac +5 Other Bac +3 Brevet Bac +5 Bac +5 Bac +5 Bac +3
[911] Bac +5 Other Bac +5 Brevet Bac +5 Bac +5 Brevet Brevet Brevet Brevet
[921] Other Bac +5 Other Other Bac +3 Other Other Bac +3 Other Brevet
[931] Brevet Brevet Bac +5 Bac +3 Other Bac +5 Bac +5 Other Bac +3 Other
[941] Brevet Bac +3 Bac +3 Brevet Brevet Bac +3 Bac +3 Other Brevet Brevet
[951] Bac +5 Bac +5 Bac +5 Brevet Bac +5 Bac +5 Bac +3 Brevet Other Brevet
[961] Bac +5 Brevet Bac +5 Bac +5 Bac +5 Bac +3 Brevet Other Bac +3 Bac +3
[971] Other Bac +5 Bac +5 Other Bac +5 Other Other Bac +5 Bac +5 Bac +3
[981] Bac +5 Bac +5 Bac +3 Brevet Brevet Bac +3 Bac +3 Other Bac +5 Other
[991] Brevet Other Bac +5 Bac +3 Other Bac +3 Bac +3 Bac +3 Bac +5 Other
[1001] Bac +5 Brevet Bac +5 Bac +5 Other Brevet Brevet Other Brevet Other
[1011] Bac +5 Bac +3 Bac +5 Bac +3 Other Other Bac +5 Bac +3 Bac +3 Other
[1021] Other Brevet Bac +3 Brevet Bac +5 Brevet Bac +3 Brevet Brevet Brevet
[1031] Brevet Other Brevet Other Other Other Other Other Bac +3 Other
[1041] Bac +5 Bac +3 Brevet Bac +5 Other Brevet Bac +3 Bac +5 Other Bac +5
[1051] Bac +5 Bac +3 Other Other Bac +5 Bac +3 Bac +5 Bac +5 Brevet Bac +5
[1061] Brevet Other Bac +3 Bac +5 Bac +3 Other Bac +3 Bac +3 Brevet Bac +5
[1071] Other Other Bac +3 Bac +5 Other Brevet Bac +5 Brevet Other Bac +3
[1081] Bac +3 Brevet Brevet Brevet Brevet Bac +3 Bac +5 Other Bac +3 Bac +3
[1091] Bac +5 Bac +3 Bac +5 Other Other Bac +3 Bac +5 Bac +5 Other Bac +5
[1101] Bac +5 Brevet Other Bac +5 Bac +3 Bac +5 Bac +3 Brevet Bac +3 Other
[1111] Bac +3 Other Brevet Brevet Bac +3 Bac +3 Brevet Bac +3 Brevet Bac +5
[1121] Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Brevet Brevet Brevet Bac +5 Bac +3
[1131] Brevet Brevet Bac +3 Bac +3 Bac +3 Brevet Bac +3 Other Bac +5 Bac +3
[1141] Bac +5 Bac +5 Other Brevet Bac +3 Other Brevet Bac +3 Brevet Other
[1151] Bac +5 Brevet Bac +3 Brevet Bac +5 Other Bac +5 Bac +5 Bac +3 Other
[1161] Other Bac +3 Other Brevet Bac +5 Bac +5 Bac +5 Bac +5 Brevet Bac +3
[1171] Other Other Bac +5 Bac +3 Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Bac +5
[1181] Other Brevet Bac +5 Brevet Bac +3 Bac +3 Bac +5 Other Other Other
[1191] Brevet Other Other Bac +5 Bac +5 Brevet Other Brevet Bac +3 Bac +5
[1201] Bac +5 Brevet Bac +5 Other Other Other Brevet Other Brevet Brevet
[1211] Bac +5 Bac +3 Other Brevet Bac +5 Bac +5 Bac +3 Bac +5 Brevet Other
[1221] Brevet Bac +3 Bac +5 Other Brevet Brevet Bac +3 Bac +3 Bac +3 Other
[1231] Other Brevet Bac +3 Bac +5 Brevet Other Bac +3 Bac +5 Other Brevet
[1241] Brevet Brevet Bac +5 Bac +5 Bac +3 Other Bac +3 Bac +3 Brevet Bac +5
[1251] Bac +5 Other Other Other Bac +3 Bac +3 Bac +3 Other Brevet Other
[1261] Brevet Bac +5 Brevet Other Brevet Bac +3 Bac +3 Brevet Bac +3 Bac +3
[1271] Bac +5 Bac +3 Other Brevet Other Bac +3 Bac +5 Bac +5 Brevet Bac +3
[1281] Other Other Bac +5 Other Brevet Other Other Bac +5 Other Bac +3
[1291] Bac +3 Other Bac +3 Bac +5 Other Other Brevet Bac +5 Brevet Bac +5
[1301] Bac +5 Brevet Bac +5 Bac +5 Brevet Other Brevet Other Brevet Bac +3
[1311] Bac +3 Brevet Other Bac +3 Brevet Bac +5 Other Brevet Other Bac +3
[1321] Bac +3 Brevet Other Bac +3 Other Other Bac +5 Other Brevet Other
[1331] Bac +5 Bac +5 Bac +5 Bac +3 Bac +5 Brevet Other Other Other Bac +5
[1341] Brevet Brevet Bac +3 Bac +5 Bac +3 Other Bac +3 Bac +3 Bac +5 Bac +3
[1351] Other Brevet Bac +3 Brevet Bac +3 Other Other Other Bac +5 Brevet
[1361] Bac +3 Bac +3 Bac +5 Other Brevet Bac +5 Other Bac +5 Bac +5 Other
[1371] Bac +5 Brevet Other Other Brevet Bac +3 Brevet Bac +5 Bac +3 Brevet
[1381] Bac +5 Brevet Bac +3 Bac +5 Bac +5 Other Other Other Bac +3 Brevet
[1391] Brevet Brevet Other Brevet Bac +3 Bac +3 Brevet Other Brevet Bac +5
[1401] Bac +5 Bac +5 Other Bac +3 Brevet Bac +3 Other Other Brevet Bac +3
[1411] Bac +3 Bac +3 Bac +5 Other Other Brevet Brevet Bac +5 Bac +5 Brevet
[1421] Other Bac +3 Bac +3 Other Bac +3 Bac +3 Bac +5 Other Bac +3 Brevet
[1431] Bac +5 Brevet Other Other Bac +3 Brevet Bac +5 Bac +5 Bac +5 Bac +5
[1441] Brevet Bac +3 Bac +5 Brevet Bac +5 Bac +5 Brevet Brevet Bac +5 Bac +3
[1451] Other Bac +3 Other Bac +5 Bac +3 Other Other Brevet Bac +3 Bac +5
[1461] Other Bac +3 Bac +3 Brevet Brevet Bac +5 Brevet Bac +5 Other Other
[1471] Other Bac +3 Brevet Bac +5 Bac +3 Brevet Brevet Bac +3 Bac +3 Bac +3
[1481] Brevet Brevet Bac +3 Bac +5 Bac +5 Other Bac +5 Brevet Brevet Other
[1491] Other Bac +5 Bac +3 Bac +3 Other Brevet Other Bac +5 Bac +5 Bac +3
[1501] Bac +3 Brevet Bac +3 Bac +5 Bac +3 Other Brevet Other Other Brevet
[1511] Brevet Bac +5 Other Other Bac +5 Brevet Bac +3 Bac +5 Brevet Bac +5
[1521] Bac +5 Bac +3 Bac +5 Bac +5 Other Bac +5 Bac +5 Bac +5 Bac +3 Bac +5
[1531] Other Brevet Bac +3 Bac +3 Bac +3 Brevet Brevet Brevet Brevet Bac +3
[1541] Other Brevet Other Bac +5 Other Other Brevet Brevet Other Bac +3
[1551] Other Brevet Other Other Other Other Other Other Brevet Bac +5
[1561] Bac +3 Brevet Bac +5 Other Brevet Other Bac +3 Other Bac +3 Bac +5
[1571] Bac +5 Bac +5 Other Bac +5 Bac +3 Other Bac +3 Brevet Bac +3 Bac +3
[1581] Bac +3 Brevet Bac +5 Bac +3 Bac +3 Bac +3 Bac +3 Brevet Bac +3 Bac +3
[1591] Brevet Other Brevet Other Bac +5 Brevet Bac +5 Other Bac +5 Other
[1601] Other Brevet Bac +5 Bac +3 Bac +3 Bac +5 Bac +3 Brevet Bac +3 Bac +3
[1611] Other Bac +3 Brevet Other Bac +3 Brevet Brevet Bac +3 Bac +3 Bac +3
[1621] Brevet Bac +5 Bac +5 Brevet Brevet Brevet Bac +5 Bac +5 Bac +5 Other
[1631] Other Brevet Bac +3 Brevet Bac +5 Other Brevet Bac +3 Brevet Bac +5
[1641] Bac +5 Bac +3 Other Other Brevet Bac +3 Brevet Bac +3 Bac +5 Bac +3
[1651] Bac +5 Bac +5 Brevet Bac +5 Brevet Other Brevet Bac +5 Bac +5 Bac +5
[1661] Bac +3 Brevet Brevet Brevet Bac +5 Brevet Bac +5 Bac +3 Bac +5 Bac +3
[1671] Bac +5 Bac +5 Brevet Bac +5 Brevet Other Bac +5 Other Bac +5 Bac +5
[1681] Other Other Brevet Brevet Brevet Other Brevet Bac +5 Bac +5 Bac +5
[1691] Bac +3 Bac +5 Bac +3 Bac +3 Brevet Bac +5 Brevet Brevet Other Other
[1701] Bac +5 Brevet Bac +3 Bac +3 Other Bac +3 Brevet Other Other Other
[1711] Other Bac +3 Bac +3 Bac +5 Other Bac +3 Brevet Bac +3 Brevet Other
[1721] Other Other Brevet Other Bac +3 Brevet Bac +5 Other Bac +3 Bac +5
[1731] Bac +3 Bac +3 Other Brevet Bac +3 Brevet Bac +5 Bac +5 Other Bac +5
[1741] Bac +3 Bac +3 Bac +5 Other Brevet Bac +5 Other Brevet Brevet Other
[1751] Bac +3 Other Bac +5 Brevet Bac +3 Brevet Bac +3 Other Brevet Brevet
[1761] Bac +3 Brevet Brevet Other Brevet Bac +3 Bac +3 Other Brevet Bac +3
[1771] Bac +5 Bac +3 Other Bac +3 Bac +3 Bac +3 Brevet Other Bac +5 Bac +3
[1781] Bac +5 Bac +5 Bac +5 Bac +5 Bac +5 Brevet Other Bac +5 Other Other
[1791] Brevet Bac +5 Brevet Brevet Brevet Bac +3 Bac +3 Bac +3 Brevet Brevet
[1801] Brevet Brevet Bac +3 Bac +3 Bac +5 Bac +5 Other Brevet Bac +5 Bac +5
[1811] Bac +5 Other Brevet Bac +3 Brevet Bac +3 Brevet Brevet Bac +3 Bac +5
[1821] Bac +3 Brevet Brevet Brevet Bac +3 Brevet Bac +3 Bac +5 Other Other
[1831] Bac +3 Brevet Bac +3 Brevet Bac +5 Brevet Bac +3 Bac +5 Brevet Brevet
[1841] Bac +5 Other Brevet Brevet Bac +3 Bac +5 Bac +5 Bac +3 Brevet Bac +3
[1851] Bac +3 Brevet Other Bac +3 Bac +3 Brevet Brevet Other Bac +5 Bac +3
[1861] Bac +3 Bac +3 Bac +5 Brevet Bac +5 Other Other Bac +5 Brevet Other
[1871] Bac +3 Bac +5 Brevet Bac +3 Bac +3 Other Other Brevet Bac +5 Bac +5
[1881] Brevet Other Bac +3 Bac +5 Other Other Bac +3 Other Bac +5 Bac +3
[1891] Bac +3 Bac +3 Bac +3 Other Brevet Bac +3 Bac +3 Bac +5 Bac +5 Brevet
[1901] Bac +3 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Brevet Bac +3 Bac +5 Bac +3
[1911] Brevet Bac +3 Bac +3 Other Brevet Other Other Bac +5 Bac +3 Brevet
[1921] Brevet Bac +5 Bac +3 Bac +3 Bac +3 Bac +3 Bac +3 Bac +3 Brevet Brevet
[1931] Bac +5 Bac +3 Brevet Other Bac +3 Other Bac +3 Other Other Other
[1941] Other Bac +5 Bac +3 Other Bac +3 Bac +3 Other Other Bac +3 Other
[1951] Other Bac +5 Other Bac +3 Bac +5 Brevet Brevet Bac +5 Bac +3 Bac +5
[1961] Bac +3 Brevet Other Bac +5 Other Bac +5 Brevet Bac +3 Bac +5 Other
[1971] Bac +5 Bac +5 Bac +5 Bac +5 Bac +5 Bac +5 Bac +5 Other Bac +5 Brevet
[1981] Other Other Brevet Other Other Bac +3 Bac +5 Bac +3 Bac +3 Brevet
[1991] Bac +5 Bac +3 Brevet Other Other Brevet Bac +5 Bac +3 Bac +5 Bac +5
[2001] Bac +3 Bac +3 Brevet Bac +5 Brevet Brevet Brevet Other Bac +5 Brevet
[2011] Other Other Brevet Bac +3 Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Bac +5
[2021] Bac +5 Bac +3 Bac +5 Other Bac +5 Other Bac +3 Bac +3 Bac +5 Bac +5
[2031] Other Other Brevet Bac +3 Brevet Bac +5 Other Bac +5 Brevet Bac +5
[2041] Other Brevet Other Other Bac +5 Bac +3 Brevet Bac +3 Brevet Bac +5
[2051] Bac +3 Bac +5 Brevet Other Other Bac +3 Bac +3 Bac +5 Bac +3 Bac +5
[2061] Bac +3 Bac +5 Brevet Other Bac +5 Bac +3 Brevet Bac +5 Bac +5 Other
[2071] Bac +5 Bac +5 Other Brevet Brevet Bac +5 Bac +5 Other Bac +5 Bac +3
[2081] Bac +3 Bac +3 Bac +5 Brevet Other Brevet Bac +3 Other Bac +5 Brevet
[2091] Other Other Bac +3 Other Other Bac +3 Bac +3 Bac +3 Bac +3 Other
[2101] Other Bac +3 Bac +3 Brevet Brevet Bac +5 Bac +3 Bac +5 Bac +5 Bac +3
[2111] Other Bac +5 Bac +3 Brevet Bac +5 Brevet Bac +5 Other Other Bac +3
[2121] Bac +5 Other Other Brevet Bac +5 Other Other Bac +3 Brevet Bac +5
[2131] Other Other Brevet Bac +3 Brevet Brevet Bac +5 Other Brevet Bac +5
[2141] Brevet Other Bac +5 Brevet Bac +5 Bac +5 Brevet Other Bac +5 Brevet
[2151] Bac +3 Bac +5 Bac +3 Bac +5 Bac +3 Brevet Bac +5 Bac +5 Bac +5 Bac +3
[2161] Bac +5 Brevet Brevet Bac +5 Bac +3 Bac +3 Bac +3 Other Bac +3 Brevet
[2171] Other Bac +5 Brevet Bac +5 Brevet Other Other Bac +5 Other Bac +5
[2181] Other Brevet Bac +5 Bac +3 Brevet Brevet Other Bac +5 Bac +5 Bac +5
[2191] Brevet Brevet Bac +3 Other Bac +5 Other Bac +5 Other Bac +3 Bac +5
[2201] Bac +5 Bac +3 Brevet Bac +5 Other Brevet Bac +3 Bac +5 Brevet Bac +3
[2211] Bac +3 Brevet Bac +3 Bac +3 Brevet Bac +3 Other Bac +3 Other Other
[2221] Other Bac +5 Brevet Brevet Other Bac +5 Bac +5 Brevet Other Bac +3
[2231] Brevet Bac +5 Bac +5 Brevet Bac +5 Bac +3 Bac +5 Other Bac +5 Bac +3
[2241] Other Brevet Other Bac +5 Other Other Brevet Bac +5 Other Bac +3
[2251] Brevet Bac +5 Bac +3 Brevet Bac +5 Bac +5 Bac +5 Bac +5 Brevet Other
[2261] Brevet Bac +5 Brevet Brevet Bac +3 Brevet Bac +5 Bac +3 Brevet Other
[2271] Bac +3 Brevet Brevet Other Bac +5 Bac +5 Bac +5 Brevet Bac +5 Brevet
[2281] Brevet Other Other Brevet Bac +3 Bac +3 Bac +5 Bac +5 Bac +3 Bac +3
[2291] Bac +3 Other Brevet Bac +5 Bac +3 Bac +5 Bac +5 Brevet Other Other
[2301] Brevet Brevet Brevet Brevet Brevet Bac +5 Brevet Other Other Bac +3
[2311] Bac +3 Bac +5 Brevet Other Bac +3 Other Brevet Brevet Brevet Bac +3
[2321] Other Brevet Bac +3 Other Bac +3 Bac +3 Other Bac +5 Bac +3 Brevet
[2331] Bac +3 Other Other Bac +5 Other Bac +5 Bac +5 Other Bac +3 Brevet
[2341] Other Bac +5 Other Brevet Other Bac +3 Brevet Bac +3 Brevet Brevet
[2351] Bac +5 Bac +5 Other Other Bac +3 Brevet Bac +5 Bac +3 Bac +3 Bac +5
[2361] Bac +5 Bac +3 Bac +3 Bac +5 Brevet Bac +5 Bac +5 Other Brevet Other
[2371] Brevet Brevet Other Bac +5 Brevet Brevet Brevet Bac +3 Other Bac +3
[2381] Bac +3 Bac +5 Brevet Bac +5 Bac +3 Brevet Bac +3 Bac +3 Brevet Bac +3
[2391] Brevet Other Bac +3 Brevet Bac +3 Other Brevet Brevet Other Other
[2401] Brevet Brevet Bac +3 Brevet Bac +5 Bac +5 Brevet Bac +3 Bac +5 Brevet
[2411] Bac +5 Bac +3 Other Bac +3 Brevet Bac +5 Bac +5 Brevet Bac +5 Other
[2421] Bac +5 Bac +5 Bac +5 Bac +3 Brevet Bac +3 Bac +3 Bac +5 Other Other
[2431] Brevet Bac +5 Other Brevet Bac +3 Bac +5 Bac +3 Bac +3 Bac +5 Bac +5
[2441] Brevet Bac +5 Other Bac +5 Brevet Other Bac +5 Bac +3 Other Brevet
[2451] Other Bac +3 Brevet Other Bac +5 Other Other Bac +3 Brevet Brevet
[2461] Brevet Bac +5 Other Bac +5 Brevet Brevet Bac +5 Bac +3 Other Bac +5
[2471] Other Brevet Bac +5 Other Brevet Bac +3 Bac +3 Brevet Brevet Brevet
[2481] Brevet Other Other Bac +5 Other Other Brevet Bac +3 Other Other
[2491] Bac +3 Bac +3 Bac +3 Bac +5 Brevet Other Bac +5 Brevet Bac +5 Bac +3
[2501] Other Other Brevet Other Bac +5 Bac +3 Bac +3 Bac +3 Brevet Brevet
[2511] Bac +3 Bac +5 Bac +5 Bac +5 Bac +5 Brevet Bac +5 Other Bac +3 Bac +3
[2521] Bac +5 Brevet Bac +3 Bac +3 Bac +3 Bac +5 Brevet Bac +5 Bac +5 Other
[2531] Brevet Bac +3 Bac +3 Other Brevet Brevet Brevet Brevet Brevet Other
[2541] Bac +5 Bac +3 Brevet Bac +3 Other Bac +5 Brevet Bac +3 Bac +3 Bac +5
[2551] Bac +3 Brevet Bac +3 Other Bac +3 Brevet Other Bac +3 Bac +3 Brevet
[2561] Bac +3 Brevet Brevet Other Other Bac +5 Bac +5 Other Bac +3 Other
[2571] Brevet Brevet Other Bac +3 Other Bac +3 Bac +5 Brevet Bac +3 Other
[2581] Other Bac +3 Other Bac +5 Bac +3 Bac +3 Bac +3 Brevet Other Brevet
[2591] Bac +3 Brevet Bac +3 Bac +5 Bac +3 Brevet Bac +3 Bac +5 Bac +5 Other
[2601] Bac +3 Brevet Bac +3 Other Bac +5 Other Other Brevet Brevet Bac +3
[2611] Other Bac +3 Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +5 Bac +3 Brevet
[2621] Brevet Brevet Brevet Other Bac +5 Bac +3 Brevet Bac +5 Bac +3 Brevet
[2631] Bac +3 Bac +5 Other Brevet Other Bac +3 Bac +3 Brevet Other Bac +5
[2641] Other Bac +5 Brevet Other Other Bac +5 Brevet Brevet Brevet Bac +3
[2651] Bac +5 Bac +3 Other Brevet Other Other Brevet Bac +3 Bac +5 Bac +3
[2661] Brevet Bac +5 Bac +3 Brevet Other Other Bac +5 Brevet Brevet Brevet
[2671] Bac +3 Other Bac +5 Bac +3 Other Bac +5 Brevet Other Brevet Other
[2681] Bac +5 Other Bac +5 Bac +5 Brevet Brevet Bac +3 Brevet Bac +3 Bac +5
[2691] Other Bac +3 Other Bac +5 Bac +5 Other Brevet Bac +3 Brevet Bac +5
[2701] Brevet Bac +3 Bac +5 Bac +5 Other Bac +5 Brevet Other Bac +5 Bac +5
[2711] Bac +5 Other Bac +5 Bac +3 Bac +3 Bac +3 Brevet Bac +3 Bac +3 Bac +3
[2721] Other Bac +3 Brevet Bac +3 Brevet Other Bac +5 Brevet Other Bac +5
[2731] Bac +3 Brevet Other Other Other Brevet Brevet Bac +5 Bac +3 Brevet
[2741] Brevet Bac +3 Other Bac +5 Brevet Bac +5 Other Bac +3 Brevet Brevet
[2751] Other Bac +5 Other Bac +5 Brevet Other Bac +3 Brevet Brevet Bac +3
[2761] Brevet Brevet Bac +5 Other Other Bac +3 Bac +5 Brevet Bac +5 Bac +3
[2771] Bac +5 Brevet Other Bac +5 Bac +5 Bac +5 Brevet Bac +3 Brevet Bac +3
[2781] Brevet Bac +5 Bac +3 Other Bac +3 Other Bac +3 Bac +5 Brevet Other
[2791] Bac +3 Other Bac +5 Brevet Other Bac +5 Other Other Brevet Brevet
[2801] Brevet Brevet Bac +5 Brevet Bac +3 Bac +3 Brevet Bac +5 Other Bac +5
[2811] Bac +3 Bac +5 Other Other Other Bac +5 Other Brevet Bac +3 Bac +3
[2821] Bac +5 Brevet Brevet Brevet Other Other Other Bac +3 Bac +3 Bac +5
[2831] Other Brevet Other Brevet Brevet Brevet Other Other Other Bac +3
[2841] Bac +5 Brevet Brevet Brevet Bac +3 Brevet Brevet Brevet Bac +3 Bac +3
[2851] Other Bac +3 Other Bac +5 Bac +3 Bac +3 Bac +5 Other Brevet Brevet
[2861] Bac +5 Other Bac +5 Brevet Brevet Brevet Bac +3 Bac +5 Bac +5 Brevet
[2871] Bac +3 Other Bac +5 Other Bac +5 Other Bac +5 Brevet Brevet Brevet
[2881] Bac +3 Other Bac +5 Bac +3 Bac +3 Other Bac +3 Brevet Other Bac +3
[2891] Brevet Bac +3 Bac +5 Brevet Bac +5 Bac +3 Brevet Other Bac +3 Bac +3
[2901] Other Other Brevet Brevet Bac +5 Other Bac +3 Bac +5 Bac +3 Bac +5
[2911] Bac +3 Brevet Other Other Bac +3 Brevet Bac +3 Bac +3 Other Bac +3
[2921] Other Other Bac +5 Bac +3 Other Bac +5 Other Brevet Bac +5 Other
[2931] Other Other Other Bac +5 Brevet Bac +5 Brevet Brevet Bac +5 Bac +5
[2941] Bac +3 Bac +5 Bac +5 Other Bac +5 Bac +3 Bac +3 Bac +3 Bac +5 Brevet
[2951] Brevet Other Bac +3 Brevet Bac +3 Brevet Other Other Brevet Bac +5
[2961] Bac +3 Other Bac +5 Bac +3 Brevet Bac +3 Brevet Brevet Brevet Brevet
[2971] Other Other Bac +3 Bac +3 Other Other Brevet Bac +5 Other Bac +3
[2981] Other Bac +5 Bac +3 Brevet Bac +3 Brevet Bac +3 Bac +5 Bac +5 Brevet
[2991] Brevet Brevet Bac +3 Brevet Bac +3 Bac +5 Brevet Other Other Other
[3001] Bac +3 Bac +5 Brevet Brevet Other Bac +5 Bac +3 Brevet Brevet Bac +3
[3011] Bac +3 Brevet Other Bac +3 Brevet Bac +3 Brevet Bac +5 Brevet Bac +5
[3021] Other Other Other Other Brevet Brevet Other Bac +5 Bac +3 Other
[3031] Other Brevet Bac +5 Bac +5 Other Brevet Brevet Bac +3 Bac +5 Brevet
[3041] Bac +5 Bac +5 Bac +3 Brevet Brevet Other Other Bac +5 Bac +5 Other
[3051] Other Other Other Brevet Other Other Other Other Bac +3 Bac +3
[3061] Bac +3 Bac +5 Other Other Bac +5 Brevet Bac +5 Bac +3 Bac +3 Bac +3
[3071] Brevet Bac +3 Brevet Bac +5 Bac +5 Brevet Brevet Brevet Other Brevet
[3081] Brevet Brevet Bac +3 Bac +3 Brevet Other Bac +3 Bac +5 Brevet Bac +5
[3091] Brevet Other Other Brevet Bac +5 Bac +5 Brevet Brevet Bac +5 Other
[3101] Bac +3 Bac +5 Bac +5 Brevet Other Other Bac +3 Other Brevet Bac +3
[3111] Bac +5 Bac +5 Other Bac +3 Bac +5 Bac +3 Other Bac +5 Other Bac +5
[3121] Bac +3 Bac +5 Brevet Other Bac +3 Other Brevet Brevet Brevet Brevet
[3131] Bac +3 Other Bac +3 Brevet Other Bac +3 Bac +3 Bac +3 Other Bac +5
[3141] Brevet Bac +5 Bac +3 Bac +5 Bac +5 Bac +3 Bac +3 Bac +5 Other Bac +3
[3151] Other Bac +3 Bac +3 Bac +5 Brevet Other Other Bac +5 Brevet Brevet
[3161] Other Bac +5 Other Bac +5 Brevet Bac +5 Brevet Other Brevet Other
[3171] Bac +3 Other Bac +5 Bac +5 Other Bac +3 Bac +3 Bac +5 Other Other
[3181] Bac +3 Brevet Bac +3 Bac +5 Other Bac +5 Bac +3 Bac +3 Bac +5 Brevet
[3191] Brevet Bac +5 Bac +5 Other Bac +5 Other Brevet Bac +5 Other Bac +3
[3201] Brevet Bac +5 Other Brevet Bac +3 Bac +5 Bac +3 Other Bac +3 Brevet
[3211] Bac +3 Bac +5 Bac +3 Bac +5 Brevet Bac +3 Bac +3 Brevet Bac +3 Brevet
[3221] Bac +5 Other Bac +5 Bac +3 Bac +5 Bac +3 Bac +5 Other Other Bac +5
[3231] Brevet Other Bac +5 Bac +5 Brevet Bac +5 Bac +3 Bac +5 Bac +3 Brevet
[3241] Bac +5 Other Brevet Brevet Bac +3 Other Bac +3 Bac +3 Bac +5 Brevet
[3251] Bac +3 Other Other Brevet Other Other Other Bac +3 Bac +5 Brevet
[3261] Brevet Other Bac +3 Other Other Bac +3 Bac +3 Bac +5 Other Bac +3
[3271] Bac +5 Bac +3 Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +3 Other Other
[3281] Bac +3 Bac +5 Brevet Bac +5 Bac +3 Brevet Bac +5 Brevet Bac +5 Bac +3
[3291] Other Brevet Bac +5 Bac +3 Other Other Brevet Bac +3 Bac +3 Bac +3
[3301] Bac +3 Bac +3 Other Bac +3 Bac +3 Other Bac +3 Bac +3 Brevet Bac +3
[3311] Other Bac +5 Other Other Other Bac +5 Bac +5 Other Bac +3 Bac +3
[3321] Brevet Brevet Other Bac +5 Other Brevet Bac +3 Other Bac +5 Brevet
[3331] Other Other Bac +5 Bac +5 Bac +5 Bac +3 Other Brevet Brevet Bac +3
[3341] Brevet Other Bac +3 Other Brevet Bac +5 Brevet Bac +3 Bac +5 Brevet
[3351] Other Bac +5 Bac +3 Brevet Bac +3 Bac +3 Bac +5 Other Brevet Other
[3361] Bac +3 Brevet Brevet Bac +5 Other Bac +5 Other Brevet Bac +5 Brevet
[3371] Other Brevet Bac +3 Brevet Other Bac +5 Other Bac +3 Bac +3 Bac +5
[3381] Bac +3 Bac +3 Brevet Brevet Other Other Bac +3 Bac +5 Bac +5 Other
[3391] Bac +3 Bac +5 Other Other Other Brevet Bac +3 Bac +3 Bac +3 Bac +3
[3401] Bac +5 Bac +3 Brevet Bac +3 Brevet Bac +3 Brevet Other Other Bac +5
[3411] Bac +3 Bac +3 Bac +3 Bac +3 Other Bac +3 Bac +5 Bac +5 Bac +5 Bac +3
[3421] Bac +3 Other Bac +3 Brevet Brevet Bac +3 Brevet Other Bac +3 Bac +3
[3431] Bac +3 Brevet Brevet Bac +5 Brevet Brevet Other Brevet Other Other
[3441] Bac +3 Bac +5 Bac +5 Bac +3 Bac +3 Bac +5 Brevet Brevet Other Brevet
[3451] Bac +5 Bac +3 Brevet Bac +3 Brevet Other Bac +5 Other Other Brevet
[3461] Bac +3 Bac +3 Bac +3 Brevet Bac +5 Bac +3 Bac +3 Brevet Bac +5 Bac +5
[3471] Bac +3 Bac +5 Brevet Other Brevet Other Bac +5 Brevet Other Bac +5
[3481] Brevet Bac +3 Brevet Bac +3 Bac +3 Brevet Bac +5 Brevet Bac +5 Other
[3491] Bac +3 Other Brevet Brevet Bac +3 Brevet Bac +5 Bac +5 Other Bac +5
[3501] Other Bac +5 Other Bac +3 Brevet Brevet Other Bac +5 Bac +3 Bac +5
[3511] Other Brevet Brevet Bac +3 Bac +5 Brevet Brevet Other Brevet Other
[3521] Other Brevet Bac +3 Bac +5 Other Brevet Brevet Other Brevet Bac +3
[3531] Bac +5 Bac +3 Brevet Bac +5 Bac +3 Brevet Brevet Bac +5 Bac +5 Bac +5
[3541] Bac +5 Bac +5 Other Other Bac +5 Bac +3 Other Brevet Other Bac +3
[3551] Bac +3 Other Other Bac +3 Bac +3 Brevet Bac +3 Brevet Other Bac +3
[3561] Bac +3 Other Bac +3 Bac +5 Bac +3 Other Bac +5 Bac +3 Bac +5 Bac +5
[3571] Bac +3 Bac +3 Brevet Bac +5 Other Other Other Bac +3 Bac +5 Other
[3581] Other Brevet Bac +3 Bac +5 Bac +3 Bac +3 Bac +3 Bac +3 Bac +5 Bac +5
[3591] Brevet Bac +5 Bac +3 Bac +3 Brevet Other Brevet Bac +5 Other Other
[3601] Brevet Brevet Bac +3 Bac +3 Bac +5 Bac +3 Bac +5 Bac +5 Brevet Other
[3611] Brevet Other Brevet Brevet Other Other Other Brevet Bac +3 Brevet
[3621] Other Bac +3 Other Other Bac +5 Other Bac +3 Bac +3 Bac +3 Brevet
[3631] Other Other Bac +3 Bac +5 Bac +3 Bac +3 Other Other Bac +5 Brevet
[3641] Other Brevet Brevet Bac +3 Other Other Other Other Other Bac +3
[3651] Brevet Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +3 Other Brevet Bac +5
[3661] Other Bac +3 Bac +5 Brevet Bac +5 Brevet Other Brevet Bac +5 Other
[3671] Brevet Brevet Bac +5 Bac +5 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Bac +5
[3681] Brevet Other Bac +3 Bac +5 Bac +3 Other Bac +5 Other Bac +3 Bac +5
[3691] Brevet Other Other Other Bac +3 Brevet Brevet Brevet Bac +3 Bac +3
[3701] Bac +5 Bac +3 Bac +3 Brevet Bac +5 Bac +3 Brevet Other Other Other
[3711] Bac +3 Brevet Other Brevet Other Bac +3 Bac +3 Other Bac +3 Other
[3721] Brevet Bac +5 Bac +5 Other Bac +3 Bac +5 Bac +5 Other Brevet Other
[3731] Bac +3 Bac +3 Bac +3 Other Bac +5 Other Bac +5 Other Bac +3 Bac +5
[3741] Bac +3 Bac +3 Other Brevet Brevet Bac +3 Other Brevet Other Bac +5
[3751] Other Brevet Bac +3 Other Bac +3 Bac +3 Brevet Bac +3 Bac +5 Other
[3761] Other Bac +5 Other Bac +3 Other Bac +5 Other Other Brevet Brevet
[3771] Bac +5 Bac +5 Brevet Other Brevet Brevet Brevet Brevet Other Bac +3
[3781] Bac +3 Bac +3 Brevet Other Brevet Bac +5 Other Other Bac +3 Bac +5
[3791] Bac +5 Brevet Brevet Bac +5 Other Brevet Bac +3 Bac +5 Other Other
[3801] Other Other Brevet Brevet Brevet Other Other Bac +3 Other Bac +5
[3811] Brevet Other Bac +3 Bac +3 Other Bac +5 Brevet Bac +5 Other Bac +3
[3821] Bac +5 Bac +3 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Bac +5 Other Other
[3831] Brevet Bac +5 Bac +3 Other Brevet Brevet Bac +5 Other Brevet Bac +3
[3841] Bac +3 Bac +5 Bac +5 Bac +5 Brevet Other Bac +5 Brevet Brevet Brevet
[3851] Other Bac +5 Brevet Brevet Brevet Brevet Bac +3 Bac +3 Bac +3 Other
[3861] Other Bac +3 Bac +3 Bac +3 Bac +5 Bac +5 Bac +5 Bac +5 Brevet Bac +3
[3871] Bac +3 Brevet Bac +5 Bac +3 Bac +3 Brevet Brevet Other Bac +3 Bac +3
[3881] Bac +3 Bac +5 Other Other Bac +3 Brevet Bac +5 Bac +3 Brevet Other
[3891] Other Other Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Other Brevet Bac +5
[3901] Bac +3 Other Bac +3 Brevet Bac +3 Bac +5 Other Bac +3 Other Bac +5
[3911] Other Brevet Brevet Other Other Bac +3 Bac +3 Other Other Brevet
[3921] Bac +3 Bac +5 Brevet Other Other Other Bac +3 Brevet Other Other
[3931] Brevet Bac +3 Bac +3 Bac +5 Bac +5 Bac +3 Brevet Bac +5 Other Bac +3
[3941] Bac +5 Bac +3 Bac +3 Bac +5 Brevet Bac +5 Brevet Other Brevet Other
[3951] Bac +5 Brevet Other Bac +5 Other Brevet Other Bac +5 Other Bac +3
[3961] Brevet Brevet Brevet Bac +5 Other Bac +5 Other Brevet Bac +5 Brevet
[3971] Other Bac +5 Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Other Other Brevet
[3981] Brevet Other Other Bac +3 Bac +5 Bac +3 Other Brevet Brevet Bac +5
[3991] Bac +3 Brevet Brevet Bac +5 Bac +5 Bac +5 Other Other Brevet Bac +5
[4001] Bac +5 Bac +3 Other Bac +3 Bac +5 Other Bac +5 Bac +3 Bac +5 Bac +5
[4011] Bac +3 Other Brevet Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Brevet Other
[4021] Bac +5 Bac +3 Brevet Bac +3 Brevet Bac +5 Bac +3 Bac +5 Bac +5 Brevet
[4031] Brevet Bac +5 Bac +5 Bac +5 Other Bac +3 Other Other Brevet Bac +3
[4041] Other Other Other Other Bac +5 Bac +5 Other Bac +3 Other Bac +5
[4051] Bac +5 Bac +3 Bac +5 Bac +3 Brevet Brevet Bac +5 Bac +5 Bac +3 Other
[4061] Bac +3 Bac +5 Bac +5 Brevet Other Bac +5 Bac +5 Bac +5 Brevet Bac +5
[4071] Other Bac +3 Other Bac +5 Bac +5 Other Other Bac +5 Bac +5 Bac +5
[4081] Bac +5 Brevet Other Bac +3 Other Bac +3 Brevet Other Bac +3 Bac +3
[4091] Brevet Bac +3 Bac +3 Bac +3 Other Bac +5 Other Other Brevet Other
[4101] Other Bac +5 Bac +5 Other Bac +3 Brevet Brevet Bac +3 Other Brevet
[4111] Bac +5 Other Other Bac +5 Other Bac +3 Brevet Bac +5 Bac +3 Bac +5
[4121] Other Brevet Other Bac +3 Other Bac +3 Bac +3 Bac +5 Bac +5 Other
[4131] Bac +3 Bac +3 Other Bac +5 Bac +3 Other Brevet Brevet Brevet Bac +5
[4141] Other Brevet Other Brevet Brevet Bac +5 Bac +5 Bac +3 Bac +3 Bac +5
[4151] Brevet Brevet Other Bac +5 Bac +5 Bac +3 Other Other Bac +3 Bac +5
[4161] Brevet Bac +5 Bac +3 Bac +5 Bac +3 Bac +3 Bac +5 Bac +3 Brevet Bac +5
[4171] Bac +3 Brevet Other Other Bac +3 Bac +5 Bac +5 Brevet Brevet Bac +5
[4181] Other Brevet Other Bac +3 Bac +5 Bac +3 Brevet Bac +3 Bac +3 Bac +5
[4191] Bac +3 Other Brevet Other Bac +5 Brevet Other Other Bac +5 Other
[4201] Brevet Other Other Bac +3 Other Bac +3 Other Bac +5 Other Other
[4211] Brevet Bac +3 Other Bac +3 Bac +5 Brevet Brevet Bac +5 Other Brevet
[4221] Other Brevet Other Other Bac +5 Brevet Bac +3 Other Bac +3 Other
[4231] Brevet Bac +5 Other Bac +3 Bac +3 Brevet Bac +3 Bac +3 Other Brevet
[4241] Other Other Bac +3 Brevet Bac +3 Bac +3 Brevet Other Bac +3 Bac +5
[4251] Brevet Bac +3 Other Brevet Bac +3 Other Bac +5 Bac +5 Other Brevet
[4261] Other Brevet Bac +5 Bac +3 Bac +3 Bac +3 Bac +3 Brevet Other Brevet
[4271] Bac +5 Bac +5 Brevet Bac +3 Brevet Bac +3 Brevet Other Bac +3 Bac +5
[4281] Bac +5 Brevet Bac +5 Other Bac +3 Brevet Bac +5 Other Bac +5 Bac +3
[4291] Bac +3 Other Bac +5 Bac +5 Bac +5 Other Brevet Bac +3 Bac +3 Bac +3
[4301] Brevet Brevet Bac +3 Other Bac +5 Other Other Brevet Brevet Bac +5
[4311] Brevet Brevet Bac +3 Bac +3 Other Bac +3 Bac +3 Other Other Bac +3
[4321] Bac +3 Other Bac +5 Bac +5 Brevet Bac +3 Bac +5 Other Brevet Bac +5
[4331] Bac +5 Bac +3 Bac +3 Brevet Other Bac +3 Other Bac +3 Other Brevet
[4341] Other Bac +5 Brevet Bac +5 Other Brevet Bac +5 Other Bac +3 Bac +5
[4351] Other Brevet Other Bac +5 Bac +5 Brevet Bac +5 Bac +5 Brevet Other
[4361] Other Other Other Bac +5 Bac +3 Other Bac +5 Bac +5 Brevet Brevet
[4371] Brevet Bac +3 Other Bac +5 Bac +3 Other Bac +5 Other Bac +3 Bac +3
[4381] Other Bac +3 Bac +3 Bac +3 Bac +3 Brevet Brevet Bac +3 Bac +5 Other
[4391] Brevet Brevet Other Other Brevet Other Other Other Other Brevet
[4401] Brevet Bac +3 Bac +3 Brevet Bac +5 Bac +3 Bac +3 Other Bac +3 Brevet
[4411] Bac +3 Bac +3 Brevet Brevet Bac +5 Bac +5 Bac +3 Bac +3 Bac +3 Other
[4421] Bac +3 Bac +5 Bac +3 Brevet Bac +5 Bac +3 Bac +5 Other Bac +3 Bac +3
[4431] Other Other Other Brevet Bac +5 Bac +5 Bac +5 Other Brevet Bac +3
[4441] Brevet Bac +5 Bac +3 Bac +5 Other Bac +5 Brevet Bac +5 Bac +3 Brevet
[4451] Other Bac +3 Bac +5 Brevet Bac +3 Bac +3 Brevet Bac +5 Other Bac +3
[4461] Bac +5 Bac +5 Brevet Brevet Other Brevet Bac +3 Brevet Other Bac +5
[4471] Other Bac +3 Other Bac +5 Brevet Brevet Other Bac +3 Brevet Bac +5
[4481] Bac +3 Bac +5 Bac +3 Bac +3 Bac +3 Other Other Bac +5 Bac +3 Other
[4491] Bac +5 Bac +5 Bac +5 Bac +3 Brevet Other Bac +5 Brevet Bac +3 Bac +5
[4501] Brevet Brevet Bac +5 Bac +5 Bac +3 Other Brevet Bac +3 Brevet Other
[4511] Bac +5 Brevet Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Other Bac +5 Brevet
[4521] Other Bac +5 Other Bac +3 Brevet Brevet Other Bac +5 Other Brevet
[4531] Other Bac +3 Other Bac +3 Brevet Other Other Other Bac +3 Brevet
[4541] Other Brevet Bac +5 Other Bac +3 Other Bac +5 Other Bac +3 Brevet
[4551] Bac +5 Bac +5 Bac +5 Bac +3 Bac +5 Bac +3 Bac +5 Brevet Bac +3 Brevet
[4561] Bac +5 Other Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Bac +5 Bac +5 Bac +5
[4571] Brevet Bac +5 Bac +5 Bac +5 Bac +5 Bac +5 Bac +3 Other Bac +5 Bac +5
[4581] Other Bac +3 Other Other Bac +3 Brevet Brevet Other Bac +5 Bac +5
[4591] Bac +3 Other Bac +3 Bac +3 Other Bac +5 Other Bac +5 Bac +5 Bac +5
[4601] Brevet Bac +5 Bac +5 Bac +5 Other Bac +3 Brevet Other Bac +5 Other
[4611] Other Brevet Bac +5 Bac +5 Other Brevet Brevet Brevet Bac +3 Bac +5
[4621] Bac +3 Other Bac +3 Bac +3 Bac +3 Other Bac +3 Brevet Bac +3 Bac +3
[4631] Bac +3 Brevet Brevet Brevet Other Other Brevet Brevet Bac +3 Bac +5
[4641] Other Other Brevet Bac +3 Brevet Bac +5 Bac +5 Bac +3 Bac +5 Bac +5
[4651] Bac +5 Brevet Other Bac +3 Brevet Other Bac +3 Brevet Other Bac +5
[4661] Bac +5 Other Bac +3 Other Other Bac +3 Bac +3 Brevet Brevet Bac +5
[4671] Other Other Brevet Brevet Bac +3 Bac +5 Brevet Other Bac +3 Bac +5
[4681] Other Brevet Bac +3 Brevet Bac +3 Bac +3 Bac +3 Bac +5 Brevet Bac +5
[4691] Brevet Bac +3 Bac +3 Bac +3 Bac +3 Other Bac +5 Brevet Brevet Bac +5
[4701] Other Bac +5 Brevet Other Brevet Other Bac +3 Bac +5 Bac +3 Brevet
[4711] Other Brevet Bac +3 Bac +3 Other Bac +3 Brevet Bac +3 Bac +3 Bac +3
[4721] Other Other Other Bac +3 Other Brevet Bac +5 Brevet Bac +5 Bac +5
[4731] Bac +5 Other Bac +3 Other Bac +5 Bac +5 Brevet Bac +5 Bac +3 Other
[4741] Bac +5 Bac +3 Other Bac +5 Other Other Bac +3 Bac +5 Bac +5 Bac +5
[4751] Bac +3 Bac +3 Other Brevet Other Other Bac +5 Other Bac +3 Bac +3
[4761] Brevet Other Bac +5 Brevet Bac +3 Bac +5 Bac +3 Other Bac +3 Bac +5
[4771] Other Other Other Other Bac +5 Brevet Bac +3 Brevet Brevet Brevet
[4781] Bac +5 Bac +5 Bac +3 Bac +5 Other Bac +3 Other Other Other Other
[4791] Other Bac +3 Bac +3 Brevet Other Other Other Other Bac +3 Bac +5
[4801] Brevet Bac +3 Bac +3 Other Bac +5 Bac +5 Brevet Brevet Brevet Brevet
[4811] Bac +5 Other Bac +5 Bac +3 Bac +3 Brevet Bac +3 Other Bac +5 Brevet
[4821] Bac +5 Bac +3 Bac +5 Bac +3 Other Brevet Bac +3 Bac +3 Other Brevet
[4831] Other Bac +3 Brevet Bac +3 Brevet Bac +3 Bac +3 Bac +3 Bac +3 Other
[4841] Other Bac +3 Bac +3 Bac +3 Brevet Brevet Brevet Brevet Bac +5 Bac +3
[4851] Bac +5 Brevet Bac +5 Bac +3 Bac +3 Brevet Other Other Bac +5 Brevet
[4861] Brevet Bac +3 Brevet Bac +3 Other Brevet Brevet Bac +5 Bac +3 Bac +5
[4871] Other Bac +3 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Bac +5 Brevet Other
[4881] Bac +3 Brevet Brevet Other Brevet Brevet Bac +5 Other Bac +5 Other
[4891] Bac +5 Bac +3 Brevet Bac +5 Bac +5 Brevet Bac +5 Bac +5 Bac +5 Bac +5
[4901] Bac +5 Bac +5 Other Bac +3 Bac +5 Bac +3 Bac +3 Other Brevet Other
[4911] Bac +3 Bac +3 Brevet Other Bac +3 Other Bac +3 Bac +3 Bac +5 Bac +3
[4921] Bac +3 Bac +5 Other Bac +3 Bac +3 Bac +3 Other Other Other Bac +3
[4931] Bac +3 Bac +3 Other Bac +3 Bac +5 Other Bac +5 Brevet Bac +3 Bac +5
[4941] Bac +5 Bac +5 Bac +5 Brevet Brevet Bac +5 Bac +3 Bac +5 Other Brevet
[4951] Bac +3 Other Bac +5 Bac +5 Other Brevet Bac +3 Other Other Brevet
[4961] Bac +3 Other Bac +5 Bac +3 Other Other Other Bac +3 Brevet Bac +5
[4971] Bac +3 Brevet Brevet Other Other Brevet Bac +3 Other Bac +3 Bac +5
[4981] Bac +5 Brevet Bac +3 Other Bac +5 Brevet Bac +5 Brevet Bac +3 Other
[4991] Bac +5 Other Bac +3 Other Bac +3 Brevet Bac +5 Bac +3 Bac +3 Bac +3
[5001] Brevet Brevet Bac +3 Brevet Brevet Brevet Bac +5 Brevet Brevet Bac +3
[5011] Other Bac +3 Bac +3 Bac +5 Brevet Brevet Brevet Bac +3 Bac +5 Bac +5
[5021] Bac +3 Bac +5 Brevet Bac +5 Brevet Bac +3 Bac +5 Brevet Bac +5 Bac +3
[5031] Bac +3 Bac +3 Bac +3 Bac +5 Bac +5 Bac +5 Brevet Bac +3 Brevet Bac +3
[5041] Other Other Bac +3 Other Bac +3 Bac +3 Brevet Other Bac +3 Brevet
[5051] Bac +5 Bac +5 Bac +5 Other Bac +3 Bac +5 Bac +3 Bac +5 Other Other
[5061] Brevet Bac +5 Other Bac +5 Bac +5 Brevet Bac +3 Bac +3 Brevet Brevet
[5071] Bac +5 Other Bac +5 Bac +3 Brevet Bac +5 Other Bac +5 Bac +5 Brevet
[5081] Bac +5 Bac +3 Brevet Brevet Brevet Brevet Brevet Brevet Other Bac +3
[5091] Bac +3 Bac +3 Bac +3 Other Bac +5 Other Bac +5 Bac +3 Bac +5 Other
[5101] Other Bac +5 Other Bac +5 Brevet Bac +5 Brevet Bac +3 Bac +5 Brevet
[5111] Bac +5 Other Other Bac +3 Bac +3 Bac +3 Bac +5 Brevet Other Brevet
[5121] Bac +5 Bac +3 Bac +3 Other Bac +3 Brevet Bac +3 Bac +5 Other Other
[5131] Bac +5 Other Brevet Other Bac +5 Bac +3 Brevet Brevet Bac +5 Bac +3
[5141] Other Brevet Brevet Bac +5 Bac +3 Brevet Other Bac +3 Bac +5 Brevet
[5151] Brevet Brevet Other Bac +5 Bac +3 Bac +5 Brevet Bac +5 Bac +5 Brevet
[5161] Other Other Brevet Brevet Bac +5 Other Bac +5 Bac +5 Bac +3 Other
[5171] Other Bac +3 Bac +5 Brevet Brevet Bac +5 Other Other Bac +3 Bac +5
[5181] Other Other Bac +5 Bac +5 Other Brevet Bac +5 Other Other Brevet
[5191] Bac +3 Bac +3 Other Other Bac +3 Other Brevet Other Other Brevet
[5201] Bac +3 Brevet Other Brevet Bac +5 Brevet Brevet Brevet Other Brevet
[5211] Other Other Other Other Bac +5 Bac +5 Other Bac +5 Brevet Brevet
[5221] Bac +3 Brevet Brevet Bac +3 Bac +5 Bac +5 Bac +5 Bac +5 Other Brevet
[5231] Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Bac +3 Bac +5 Brevet Bac +3 Bac +3
[5241] Other Other Other Bac +3 Bac +3 Other Brevet Bac +5 Brevet Other
[5251] Bac +3 Bac +5 Other Bac +5 Bac +3 Brevet Bac +3 Bac +5 Bac +5 Bac +3
[5261] Other Bac +5 Bac +3 Bac +3 Bac +5 Bac +5 Brevet Bac +5 Brevet Other
[5271] Other Brevet Brevet Bac +3 Other Brevet Other Other Bac +3 Bac +3
[5281] Bac +3 Bac +3 Bac +5 Brevet Bac +5 Other Other Bac +5 Brevet Bac +5
[5291] Bac +3 Brevet Bac +5 Bac +5 Brevet Bac +5 Bac +3 Other Brevet Bac +3
[5301] Bac +3 Bac +5 Brevet Brevet Other Bac +5 Other Bac +5 Brevet Bac +5
[5311] Bac +5 Other Bac +3 Brevet Brevet Bac +3 Brevet Bac +5 Other Bac +5
[5321] Brevet Brevet Bac +5 Bac +3 Brevet Brevet Bac +3 Bac +5 Bac +3 Brevet
[5331] Brevet Bac +3 Bac +3 Other Bac +5 Brevet Bac +3 Bac +5 Brevet Bac +3
[5341] Bac +3 Brevet Brevet Bac +5 Bac +3 Other Bac +3 Brevet Bac +5 Bac +3
[5351] Bac +5 Brevet Bac +5 Bac +3 Bac +3 Bac +3 Brevet Bac +5 Other Other
[5361] Bac +3 Brevet Other Bac +3 Brevet Brevet Bac +3 Bac +5 Bac +3 Other
[5371] Brevet Brevet Bac +5 Brevet Other Bac +5 Bac +5 Bac +5 Bac +3 Other
[5381] Bac +5 Other Bac +3 Other Brevet Bac +3 Bac +3 Other Bac +3 Other
[5391] Bac +3 Brevet Brevet Other Brevet Brevet Bac +3 Bac +5 Bac +5 Brevet
[5401] Bac +5 Brevet Bac +5 Bac +5 Other Bac +3 Bac +3 Other Brevet Bac +3
[5411] Bac +5 Other Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +3 Bac +5 Other
[5421] Bac +3 Bac +5 Brevet Bac +5 Other Other Bac +5 Bac +5 Brevet Other
[5431] Bac +3 Bac +3 Other Bac +3 Bac +5 Brevet Other Brevet Bac +5 Brevet
[5441] Bac +5 Bac +3 Brevet Brevet Bac +5 Brevet Other Bac +5 Other Brevet
[5451] Other Brevet Bac +5 Brevet Brevet Bac +5 Bac +3 Bac +5 Bac +3 Brevet
[5461] Other Bac +5 Brevet Brevet Brevet Bac +5 Other Bac +5 Brevet Bac +3
[5471] Brevet Bac +5 Bac +3 Bac +3 Bac +3 Bac +5 Bac +5 Bac +5 Brevet Brevet
[5481] Bac +5 Bac +3 Bac +5 Other Bac +5 Other Other Bac +5 Bac +5 Brevet
[5491] Other Bac +5 Bac +5 Bac +5 Other Other Bac +3 Bac +5 Other Brevet
[5501] Other Bac +5 Other Bac +5 Brevet Other Bac +5 Bac +3 Bac +5 Bac +5
[5511] Bac +3 Bac +5 Bac +3 Bac +3 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Bac +5
[5521] Other Brevet Bac +5 Brevet Other Other Bac +3 Brevet Brevet Bac +3
[5531] Other Bac +3 Other Bac +5 Bac +3 Bac +5 Bac +5 Other Bac +3 Bac +5
[5541] Bac +5 Brevet Brevet Brevet Bac +5 Brevet Brevet Other Bac +5 Brevet
[5551] Brevet Other Bac +5 Other Bac +3 Other Bac +5 Other Bac +5 Other
[5561] Bac +3 Bac +3 Brevet Brevet Other Brevet Other Brevet Brevet Other
[5571] Brevet Brevet Brevet Brevet Other Bac +3 Bac +5 Other Other Bac +5
[5581] Bac +5 Bac +5 Bac +5 Other Other Bac +5 Bac +3 Brevet Brevet Other
[5591] Bac +5 Brevet Other Bac +3 Bac +5 Other Brevet Bac +5 Brevet Brevet
[5601] Brevet Brevet Brevet Bac +3 Bac +5 Brevet Bac +5 Bac +3 Other Brevet
[5611] Bac +3 Other Other Bac +5 Brevet Other Brevet Brevet Bac +5 Bac +5
[5621] Bac +5 Bac +5 Other Bac +3 Brevet Bac +3 Bac +3 Bac +3 Other Bac +3
[5631] Bac +5 Bac +5 Bac +3 Brevet Bac +3 Other Bac +3 Bac +3 Other Bac +3
[5641] Bac +5 Bac +5 Brevet Brevet Bac +5 Brevet Brevet Brevet Brevet Other
[5651] Other Brevet Bac +5 Bac +3 Bac +5 Bac +3 Other Brevet Bac +5 Bac +5
[5661] Other Bac +3 Bac +5 Brevet Bac +5 Bac +3 Other Brevet Bac +5 Bac +5
[5671] Bac +3 Brevet Brevet Bac +3 Bac +5 Bac +3 Brevet Bac +5 Brevet Brevet
[5681] Bac +3 Other Brevet Brevet Bac +3 Other Bac +5 Bac +3 Bac +3 Brevet
[5691] Other Brevet Bac +3 Bac +5 Bac +3 Bac +3 Other Other Other Other
[5701] Brevet Bac +5 Bac +5 Brevet Bac +5 Bac +3 Brevet Other Brevet Bac +3
[5711] Brevet Other Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Brevet Brevet Bac +5
[5721] Bac +5 Other Bac +5 Brevet Bac +5 Other Brevet Brevet Bac +3 Bac +3
[5731] Bac +5 Other Other Bac +3 Other Brevet Other Bac +3 Brevet Other
[5741] Other Brevet Bac +3 Other Bac +5 Other Brevet Bac +5 Other Other
[5751] Brevet Bac +5 Bac +3 Brevet Bac +5 Other Bac +3 Bac +5 Bac +5 Other
[5761] Bac +3 Bac +3 Other Bac +3 Bac +3 Bac +5 Other Other Bac +5 Bac +5
[5771] Bac +3 Brevet Brevet Brevet Other Bac +5 Bac +3 Brevet Bac +3 Bac +3
[5781] Brevet Bac +5 Bac +3 Bac +5 Other Other Other Bac +3 Other Bac +3
[5791] Brevet Bac +5 Bac +5 Other Brevet Other Brevet Bac +5 Bac +3 Other
[5801] Bac +3 Brevet Other Bac +5 Bac +3 Bac +3 Bac +5 Bac +3 Brevet Bac +3
[5811] Brevet Other Bac +5 Other Bac +3 Brevet Bac +3 Brevet Bac +5 Other
[5821] Bac +5 Bac +5 Other Bac +5 Other Bac +5 Other Brevet Other Bac +5
[5831] Other Bac +5 Bac +3 Bac +5 Brevet Brevet Other Brevet Bac +5 Brevet
[5841] Bac +5 Bac +3 Bac +5 Other Bac +3 Other Bac +5 Bac +3 Bac +3 Bac +3
[5851] Bac +5 Bac +3 Bac +5 Other Other Bac +3 Bac +5 Bac +3 Bac +3 Bac +5
[5861] Brevet Brevet Brevet Bac +3 Bac +3 Brevet Brevet Bac +5 Bac +3 Bac +3
[5871] Bac +5 Other Other Brevet Bac +5 Bac +3 Bac +5 Bac +5 Bac +3 Bac +3
[5881] Bac +5 Other Other Brevet Other Bac +5 Brevet Other Bac +3 Bac +3
[5891] Brevet Brevet Bac +5 Brevet Bac +5 Other Other Bac +5 Other Other
[5901] Bac +3 Bac +5 Other Bac +5 Bac +5 Bac +5 Brevet Bac +3 Bac +3 Bac +5
[5911] Other Bac +3 Bac +5 Brevet Bac +5 Other Bac +5 Other Bac +5 Other
[5921] Bac +3 Other Bac +3 Bac +5 Other Brevet Bac +3 Brevet Brevet Bac +3
[5931] Other Other Brevet Bac +3 Bac +5 Bac +3 Bac +5 Other Brevet Bac +5
[5941] Bac +3 Brevet Bac +3 Bac +3 Bac +3 Bac +5 Brevet Bac +5 Bac +5 Brevet
[5951] Other Other Brevet Bac +5 Brevet Other Other Bac +3 Other Brevet
[5961] Brevet Other Bac +3 Bac +5 Other Other Bac +3 Other Bac +3 Bac +5
[5971] Bac +5 Bac +5 Other Bac +5 Bac +3 Bac +3 Other Bac +3 Bac +3 Bac +3
[5981] Bac +5 Bac +5 Other Brevet Bac +3 Other Bac +3 Bac +5 Bac +3 Bac +5
[5991] Bac +5 Brevet Bac +5 Bac +3 Bac +3 Other Brevet Other Bac +5 Other
[6001] Bac +3 Other Bac +3 Bac +3 Other Other Brevet Bac +3 Brevet Brevet
[6011] Other Bac +3 Bac +3 Other Bac +3 Bac +5 Other Bac +3 Other Bac +5
[6021] Bac +3 Bac +3 Bac +3 Other Other Bac +3 Bac +5 Bac +3 Bac +3 Bac +3
[6031] Other Other Brevet Bac +3 Bac +5 Brevet Other Other Brevet Other
[6041] Bac +5 Bac +5 Bac +5 Bac +3 Bac +5 Bac +3 Brevet Other Bac +5 Other
[6051] Other Brevet Bac +3 Brevet Other Bac +5 Bac +3 Brevet Bac +3 Bac +3
[6061] Other Other Brevet Bac +3 Bac +5 Bac +5 Brevet Bac +3 Other Bac +5
[6071] Brevet Other Other Bac +3 Brevet Bac +5 Bac +3 Other Brevet Brevet
[6081] Brevet Brevet Brevet Other Brevet Brevet Other Brevet Brevet Bac +5
[6091] Brevet Bac +3 Brevet Brevet Bac +5 Bac +5 Bac +3 Bac +5 Bac +5 Bac +5
[6101] Bac +3 Bac +5 Bac +5 Bac +5 Brevet Bac +3 Brevet Brevet Other Bac +3
[6111] Other Brevet Bac +3 Other Bac +5 Brevet Bac +5 Brevet Brevet Bac +5
[6121] Other Brevet Bac +5 Bac +3 Other Bac +3 Bac +5 Brevet Bac +3 Bac +3
[6131] Bac +5 Bac +3 Bac +3 Brevet Other Bac +3 Bac +3 Brevet Bac +3 Bac +5
[6141] Brevet Brevet Bac +5 Other Other Bac +3 Brevet Bac +5 Other Bac +3
[6151] Bac +3 Brevet Bac +3 Bac +3 Brevet Bac +5 Bac +5 Other Other Other
[6161] Other Brevet Bac +3 Other Bac +3 Bac +5 Bac +5 Brevet Bac +5 Brevet
[6171] Brevet Bac +5 Brevet Other Bac +3 Other Other Bac +5 Brevet Bac +5
[6181] Bac +3 Other Bac +5 Bac +3 Brevet Other Bac +5 Bac +5 Bac +5 Bac +5
[6191] Bac +5 Bac +5 Bac +5 Other Brevet Brevet Bac +3 Bac +5 Brevet Other
[6201] Other Bac +5 Other Other Brevet Bac +3 Bac +3 Bac +5 Other Brevet
[6211] Other Bac +3 Bac +5 Bac +5 Bac +3 Brevet Brevet Bac +5 Other Other
[6221] Other Bac +5 Bac +3 Bac +3 Bac +3 Other Brevet Brevet Bac +5 Bac +5
[6231] Bac +3 Bac +3 Bac +3 Other Bac +3 Brevet Bac +3 Bac +3 Brevet Other
[6241] Bac +3 Bac +5 Bac +5 Other Other Bac +3 Brevet Brevet Brevet Other
[6251] Bac +3 Other Bac +3 Bac +5 Brevet Bac +5 Bac +5 Other Bac +3 Other
[6261] Bac +3 Bac +3 Other Brevet Bac +3 Bac +5 Bac +5 Bac +3 Bac +3 Bac +3
[6271] Bac +3 Brevet Bac +3 Bac +5 Other Brevet Bac +5 Bac +3 Brevet Brevet
[6281] Other Bac +3 Bac +5 Brevet Other Bac +5 Bac +5 Bac +3 Bac +5 Bac +5
[6291] Bac +3 Bac +5 Brevet Bac +5 Other Brevet Bac +5 Bac +3 Bac +3 Brevet
[6301] Bac +5 Brevet Other Brevet Brevet Bac +5 Bac +5 Bac +3 Bac +5 Bac +5
[6311] Bac +3 Bac +5 Bac +5 Bac +5 Brevet Other Bac +3 Bac +3 Bac +5 Bac +3
[6321] Other Bac +3 Other Bac +5 Brevet Bac +3 Bac +3 Bac +5 Brevet Brevet
[6331] Bac +5 Bac +5 Brevet Bac +5 Bac +3 Other Other Brevet Brevet Other
[6341] Brevet Brevet Other Bac +5 Other Brevet Bac +3 Bac +5 Brevet Bac +3
[6351] Bac +5 Other Bac +3 Brevet Bac +3 Bac +5 Brevet Brevet Bac +3 Other
[6361] Brevet Brevet Bac +5 Bac +5 Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Bac +5
[6371] Bac +5 Brevet Brevet Bac +3 Bac +3 Other Brevet Other Other Bac +3
[6381] Bac +5 Bac +3 Other Brevet Other Bac +5 Bac +5 Other Bac +5 Other
[6391] Other Bac +3 Other Brevet Brevet Bac +3 Other Bac +5 Bac +3 Bac +5
[6401] Brevet Bac +5 Other Brevet Bac +5 Other Bac +3 Bac +5 Bac +5 Brevet
[6411] Bac +3 Other Other Bac +3 Brevet Bac +5 Brevet Other Bac +3 Brevet
[6421] Bac +5 Bac +3 Brevet Other Bac +3 Bac +3 Brevet Other Brevet Bac +5
[6431] Other Bac +3 Bac +3 Bac +3 Bac +5 Bac +5 Brevet Brevet Bac +3 Bac +3
[6441] Brevet Bac +5 Brevet Other Bac +3 Brevet Brevet Bac +5 Bac +5 Bac +5
[6451] Brevet Other Other Brevet Bac +3 Other Other Bac +5 Other Bac +5
[6461] Bac +5 Bac +3 Other Bac +5 Bac +5 Other Bac +3 Brevet Other Bac +3
[6471] Other Bac +3 Bac +3 Bac +5 Bac +3 Bac +3 Brevet Brevet Bac +3 Bac +3
[6481] Bac +3 Bac +5 Bac +3 Brevet Other Brevet Other Other Other Other
[6491] Other Bac +3 Other Bac +3 Brevet Bac +5 Bac +5 Bac +3 Bac +5 Other
[6501] Bac +5 Bac +5 Bac +5 Brevet Bac +5 Other Bac +5 Bac +5 Other Bac +5
[6511] Bac +5 Bac +3 Bac +3 Brevet Bac +5 Other Bac +5 Brevet Bac +5 Bac +5
[6521] Other Brevet Brevet Other Bac +3 Bac +3 Other Bac +3 Other Other
[6531] Brevet Bac +5 Brevet Bac +3 Bac +3 Brevet Other Bac +5 Other Brevet
[6541] Bac +5 Brevet Other Other Other Bac +3 Brevet Other Brevet Bac +3
[6551] Bac +3 Bac +3 Bac +5 Other Bac +3 Brevet Brevet Brevet Other Bac +3
[6561] Other Brevet Brevet Bac +3 Brevet Brevet Bac +5 Bac +5 Bac +3 Bac +5
[6571] Bac +3 Bac +5 Other Bac +5 Brevet Brevet Bac +5 Bac +3 Bac +5 Bac +3
[6581] Other Bac +3 Brevet Brevet Brevet Bac +5 Bac +5 Bac +5 Bac +3 Bac +5
[6591] Bac +3 Bac +5 Brevet Bac +3 Bac +3 Bac +3 Bac +3 Other Bac +3 Brevet
[6601] Bac +5 Other Bac +3 Other Bac +3 Bac +3 Bac +5 Brevet Bac +5 Brevet
[6611] Bac +3 Bac +3 Bac +5 Other Brevet Other Other Bac +5 Other Brevet
[6621] Other Bac +5 Brevet Bac +3 Brevet Other Bac +3 Bac +3 Other Other
[6631] Other Bac +5 Bac +3 Bac +3 Other Bac +5 Other Bac +3 Brevet Brevet
[6641] Bac +5 Brevet Bac +3 Bac +5 Bac +3 Brevet Bac +5 Bac +5 Bac +5 Bac +3
[6651] Brevet Bac +5 Other Bac +3 Other Other Bac +3 Brevet Brevet Bac +3
[6661] Bac +3 Other Bac +5 Other Bac +5 Brevet Bac +5 Brevet Bac +3 Other
[6671] Bac +3 Bac +3 Bac +3 Bac +3 Other Brevet Bac +5 Brevet Other Other
[6681] Bac +5 Other Other Bac +5 Other Other Other Other Brevet Other
[6691] Bac +3 Other Other Bac +5 Brevet Bac +3 Brevet Brevet Bac +5 Bac +3
[6701] Brevet Brevet Bac +5 Bac +3 Other Bac +5 Brevet Bac +5 Other Brevet
[6711] Brevet Brevet Bac +5 Bac +5 Bac +3 Bac +3 Other Brevet Brevet Bac +3
[6721] Other Bac +5 Bac +5 Bac +5 Brevet Brevet Bac +5 Other Bac +5 Bac +3
[6731] Other Other Other Bac +5 Other Bac +5 Bac +5 Bac +3 Other Bac +3
[6741] Bac +3 Brevet Bac +5 Bac +5 Brevet Bac +5 Bac +5 Bac +3 Bac +3 Brevet
[6751] Bac +5 Other Bac +5 Other Brevet Bac +5 Bac +5 Bac +3 Bac +5 Brevet
[6761] Bac +3 Brevet Bac +5 Bac +5 Other Bac +3 Other Brevet Bac +3 Bac +3
[6771] Brevet Bac +3 Bac +5 Bac +3 Other Bac +5 Brevet Bac +5 Bac +5 Other
[6781] Bac +3 Other Brevet Bac +5 Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Bac +3
[6791] Brevet Other Bac +5 Bac +5 Brevet Brevet Brevet Bac +3 Other Other
[6801] Bac +3 Brevet Brevet Other Bac +5 Bac +5 Brevet Bac +3 Bac +3 Bac +5
[6811] Bac +5 Bac +5 Other Bac +3 Other Other Bac +3 Other Other Brevet
[6821] Bac +3 Bac +3 Other Bac +3 Bac +3 Other Brevet Bac +5 Bac +3 Other
[6831] Bac +5 Brevet Bac +5 Brevet Brevet Brevet Bac +3 Other Bac +3 Other
[6841] Bac +3 Bac +3 Brevet Brevet Other Other Brevet Other Brevet Other
[6851] Bac +5 Bac +5 Other Bac +3 Bac +3 Brevet Bac +3 Other Brevet Bac +5
[6861] Brevet Bac +5 Brevet Bac +5 Other Bac +5 Bac +3 Brevet Other Other
[6871] Brevet Bac +5 Bac +5 Bac +3 Bac +3 Bac +5 Brevet Bac +5 Bac +5 Brevet
[6881] Bac +3 Other Other Bac +3 Bac +5 Bac +3 Other Bac +5 Other Bac +3
[6891] Other Bac +5 Bac +3 Bac +3 Bac +3 Other Bac +3 Brevet Bac +5 Bac +5
[6901] Brevet Bac +3 Bac +3 Brevet Other Bac +3 Bac +3 Brevet Brevet Other
[6911] Bac +3 Bac +5 Brevet Bac +3 Bac +3 Bac +5 Bac +3 Other Brevet Bac +3
[6921] Brevet Brevet Brevet Bac +5 Other Bac +3 Other Bac +3 Bac +5 Other
[6931] Bac +5 Bac +5 Brevet Bac +3 Bac +3 Brevet Brevet Other Bac +5 Brevet
[6941] Other Bac +5 Other Bac +5 Brevet Other Bac +3 Bac +3 Brevet Bac +3
[6951] Brevet Brevet Bac +5 Bac +3 Bac +5 Other Brevet Bac +5 Brevet Bac +5
[6961] Bac +5 Brevet Other Bac +3 Brevet Brevet Brevet Bac +5 Other Brevet
[6971] Bac +5 Bac +3 Brevet Brevet Brevet Bac +3 Other Bac +3 Other Bac +5
[6981] Bac +3 Other Brevet Bac +5 Bac +5 Brevet Bac +3 Bac +3 Other Bac +5
[6991] Other Brevet Bac +5 Bac +3 Bac +5 Brevet Other Bac +3 Other Bac +3
[7001] Other Other Brevet Brevet Bac +3 Bac +3 Bac +5 Brevet Bac +3 Other
[7011] Bac +3 Other Bac +5 Other Bac +5 Bac +5 Bac +5 Other Bac +5 Other
[7021] Bac +3 Brevet Bac +5 Brevet Bac +5 Bac +3 Other Bac +5 Other Bac +3
[7031] Brevet Brevet Other Bac +5 Brevet Other Bac +5 Bac +3 Bac +3 Other
[7041] Other Bac +5 Bac +5 Bac +3 Other Bac +3 Other Brevet Bac +3 Brevet
[7051] Bac +3 Brevet Brevet Other Bac +5 Bac +5 Bac +3 Other Bac +3 Bac +3
[7061] Other Bac +3 Other Other Other Brevet Bac +5 Other Brevet Brevet
[7071] Other Other Bac +3 Brevet Brevet Bac +5 Bac +3 Brevet Other Brevet
[7081] Bac +3 Bac +5 Brevet Other Other Bac +5 Other Other Other Brevet
[7091] Other Other Bac +5 Bac +3 Bac +5 Other Bac +3 Bac +3 Bac +5 Brevet
[7101] Other Brevet Bac +3 Other Bac +5 Other Other Bac +5 Bac +5 Bac +3
[7111] Bac +3 Other Bac +3 Other Bac +3 Brevet Other Other Bac +5 Brevet
[7121] Bac +5 Bac +5 Brevet Other Bac +3 Bac +3 Brevet Bac +5 Bac +5 Brevet
[7131] Brevet Other Bac +5 Brevet Brevet Bac +5 Bac +5 Brevet Other Bac +3
[7141] Bac +3 Brevet Other Brevet Brevet Bac +5 Bac +3 Brevet Bac +5 Brevet
[7151] Bac +5 Brevet Other Bac +3 Other Bac +5 Other Brevet Bac +5 Brevet
[7161] Other Brevet Other Bac +3 Bac +3 Bac +5 Bac +3 Bac +3 Brevet Bac +3
[7171] Other Bac +3 Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Other Bac +5 Bac +3
[7181] Other Brevet Brevet Bac +5 Brevet Brevet Other Other Brevet Bac +5
[7191] Brevet Brevet Bac +5 Other Other Other Bac +3 Brevet Bac +5 Brevet
[7201] Brevet Bac +5 Other Bac +5 Bac +3 Brevet Bac +5 Bac +3 Bac +5 Other
[7211] Bac +3 Bac +5 Bac +5 Other Brevet Brevet Bac +3 Bac +5 Bac +3 Other
[7221] Other Brevet Bac +5 Bac +5 Bac +3 Bac +5 Brevet Bac +3 Bac +3 Brevet
[7231] Brevet Other Bac +3 Brevet Bac +5 Other Bac +5 Brevet Bac +5 Other
[7241] Brevet Bac +5 Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Bac +5 Brevet Bac +5
[7251] Bac +3 Bac +3 Brevet Bac +3 Other Other Brevet Other Other Brevet
[7261] Brevet Bac +3 Brevet Bac +3 Bac +5 Other Bac +3 Brevet Brevet Other
[7271] Other Bac +3 Bac +5 Bac +5 Bac +3 Bac +3 Bac +3 Brevet Bac +5 Bac +3
[7281] Bac +3 Other Brevet Other Other Bac +5 Other Bac +5 Other Other
[7291] Bac +3 Bac +3 Bac +5 Other Brevet Other Brevet Bac +5 Other Bac +5
[7301] Bac +3 Other Bac +5 Bac +3 Bac +3 Other Other Brevet Brevet Brevet
[7311] Other Bac +5 Other Bac +3 Bac +5 Bac +3 Bac +3 Bac +5 Bac +5 Bac +3
[7321] Other Other Bac +3 Other Brevet Bac +3 Bac +3 Bac +5 Brevet Bac +3
[7331] Bac +3 Bac +5 Bac +3 Bac +5 Other Bac +3 Bac +3 Other Bac +3 Bac +3
[7341] Bac +3 Bac +3 Bac +3 Other Brevet Brevet Other Brevet Bac +3 Bac +5
[7351] Other Bac +3 Other Brevet Bac +3 Other Other Brevet Other Bac +5
[7361] Bac +3 Other Bac +3 Bac +5 Bac +3 Other Brevet Bac +3 Brevet Bac +5
[7371] Bac +3 Brevet Bac +5 Bac +5 Bac +5 Brevet Bac +3 Bac +3 Bac +3 Bac +3
[7381] Other Other Brevet Bac +5 Bac +5 Bac +3 Brevet Bac +5 Brevet Bac +3
[7391] Bac +5 Other Bac +3 Other Bac +3 Bac +5 Other Other Bac +3 Bac +3
[7401] Bac +3 Bac +3 Brevet Other Brevet Brevet Brevet Other Bac +3 Other
[7411] Bac +3 Bac +5 Brevet Brevet Other Bac +3 Brevet Brevet Other Bac +3
[7421] Other Other Bac +3 Other Bac +3 Bac +5 Other Other Bac +5 Brevet
[7431] Brevet Other Bac +5 Bac +3 Bac +3 Other Bac +5 Other Other Bac +3
[7441] Bac +3 Bac +3 Bac +5 Other Bac +3 Other Brevet Bac +3 Bac +5 Bac +5
[7451] Other Other Other Bac +5 Bac +3 Bac +5 Bac +5 Bac +3 Bac +5 Bac +5
[7461] Bac +3 Bac +5 Brevet Bac +5 Bac +5 Other Brevet Bac +3 Bac +5 Bac +3
[7471] Other Bac +3 Brevet Brevet Other Bac +3 Bac +5 Brevet Bac +3 Bac +3
[7481] Brevet Bac +5 Bac +3 Bac +5 Bac +5 Bac +5 Bac +3 Brevet Bac +5 Bac +3
[7491] Brevet Bac +5 Bac +3 Other Bac +5 Other Brevet Other Bac +3 Bac +5
[7501] Other Bac +5 Bac +3 Other Other Bac +5 Brevet Brevet Bac +5 Bac +5
[7511] Brevet Other Brevet Bac +3 Bac +3 Bac +5 Bac +3 Bac +5 Brevet Bac +5
[7521] Bac +5 Bac +5 Bac +5 Other Other Bac +3 Other Bac +3 Brevet Other
[7531] Bac +3 Brevet Other Brevet Other Bac +3 Bac +3 Bac +3 Bac +5 Brevet
[7541] Bac +3 Bac +5 Brevet Bac +5 Bac +3 Other Bac +3 Other Other Brevet
[7551] Bac +3 Other Bac +3 Other Bac +3 Other Other Bac +5 Brevet Bac +3
[7561] Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Other Bac +5 Brevet Other Brevet
[7571] Other Brevet Brevet Bac +5 Brevet Bac +3 Brevet Brevet Bac +3 Brevet
[7581] Other Brevet Bac +3 Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Other Bac +3
[7591] Bac +3 Bac +3 Other Brevet Brevet Other Bac +5 Bac +3 Brevet Bac +3
[7601] Bac +5 Brevet Other Bac +3 Bac +5 Other Bac +5 Bac +3 Bac +5 Bac +5
[7611] Brevet Other Other Other Bac +5 Brevet Bac +5 Other Bac +3 Brevet
[7621] Other Brevet Brevet Bac +5 Brevet Bac +3 Bac +3 Bac +5 Bac +3 Bac +5
[7631] Bac +5 Bac +3 Bac +3 Bac +5 Bac +5 Brevet Other Bac +3 Other Other
[7641] Bac +5 Brevet Bac +3 Other Other Other Bac +5 Brevet Bac +3 Bac +3
[7651] Bac +3 Other Bac +3 Bac +3 Brevet Bac +5 Bac +5 Brevet Bac +3 Bac +5
[7661] Other Bac +3 Bac +5 Brevet Bac +3 Other Brevet Bac +3 Brevet Bac +3
[7671] Brevet Other Other Bac +5 Brevet Bac +5 Bac +3 Other Bac +5 Bac +5
[7681] Brevet Brevet Other Bac +3 Brevet Other Brevet Bac +3 Bac +3 Other
[7691] Other Other Bac +5 Brevet Brevet Bac +3 Bac +5 Other Bac +5 Bac +3
[7701] Other Bac +3 Other Other Bac +5 Other Bac +3 Bac +5 Other Bac +3
[7711] Bac +3 Bac +5 Other Brevet Other Brevet Brevet Brevet Other Bac +3
[7721] Bac +5 Bac +5 Bac +3 Other Other Bac +3 Bac +5 Other Brevet Bac +3
[7731] Brevet Bac +3 Bac +5 Brevet Other Other Other Brevet Bac +3 Bac +3
[7741] Bac +5 Bac +3 Brevet Other Brevet Brevet Other Bac +5 Other Other
[7751] Bac +5 Other Bac +3 Other Brevet Other Other Bac +3 Bac +3 Brevet
[7761] Bac +5 Other Other Other Other Bac +3 Other Brevet Brevet Bac +5
[7771] Brevet Other Bac +3 Other Bac +5 Brevet Brevet Bac +5 Brevet Bac +3
[7781] Other Other Bac +3 Brevet Brevet Bac +3 Brevet Bac +5 Other Bac +3
[7791] Bac +5 Bac +3 Brevet Bac +5 Brevet Other Other Brevet Brevet Other
[7801] Other Bac +5 Bac +3 Brevet Brevet Brevet Bac +5 Brevet Bac +5 Bac +5
[7811] Bac +5 Bac +5 Bac +3 Brevet Bac +3 Other Brevet Brevet Brevet Bac +3
[7821] Bac +3 Bac +5 Bac +5 Other Bac +3 Bac +3 Bac +5 Other Bac +5 Brevet
[7831] Brevet Bac +3 Brevet Other Brevet Bac +5 Other Bac +5 Bac +5 Bac +3
[7841] Bac +3 Bac +5 Bac +5 Brevet Bac +5 Other Brevet Bac +5 Brevet Bac +3
[7851] Other Bac +3 Brevet Bac +5 Bac +3 Brevet Bac +3 Other Bac +5 Other
[7861] Bac +3 Other Brevet Other Other Brevet Bac +3 Other Other Other
[7871] Other Bac +5 Bac +3 Bac +3 Other Bac +5 Other Bac +3 Bac +3 Brevet
[7881] Bac +5 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Other Bac +3 Brevet Bac +5
[7891] Brevet Other Other Bac +5 Bac +5 Bac +5 Brevet Brevet Brevet Brevet
[7901] Bac +3 Other Bac +5 Other Bac +3 Brevet Bac +5 Bac +5 Brevet Brevet
[7911] Bac +3 Bac +5 Bac +3 Brevet Bac +3 Bac +5 Other Bac +5 Bac +5 Bac +3
[7921] Bac +3 Bac +3 Bac +5 Bac +3 Bac +3 Bac +5 Other Other Bac +3 Brevet
[7931] Bac +3 Bac +3 Bac +3 Other Bac +3 Brevet Bac +3 Bac +5 Bac +5 Other
[7941] Brevet Bac +3 Bac +5 Other Brevet Bac +5 Brevet Bac +3 Other Bac +5
[7951] Bac +5 Brevet Other Bac +3 Bac +3 Other Brevet Bac +5 Bac +3 Other
[7961] Other Other Bac +3 Other Bac +3 Brevet Brevet Bac +3 Brevet Brevet
[7971] Brevet Bac +5 Brevet Brevet Bac +5 Other Other Brevet Other Other
[7981] Other Bac +3 Bac +3 Other Brevet Brevet Brevet Bac +5 Bac +5 Bac +3
[7991] Bac +5 Bac +3 Bac +3 Brevet Other Bac +5 Brevet Bac +5 Brevet Other
[8001] Bac +3 Bac +5 Bac +3 Other Brevet Bac +5 Other Brevet Brevet Brevet
[8011] Brevet Brevet Bac +5 Bac +3 Bac +5 Bac +5 Bac +3 Other Brevet Other
[8021] Other Other Bac +5 Bac +5 Bac +5 Bac +5 Other Bac +5 Bac +3 Other
[8031] Brevet Other Other Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Other Other
[8041] Brevet Bac +5 Brevet Bac +3 Other Other Other Brevet Bac +5 Bac +5
[8051] Bac +3 Bac +3 Bac +3 Brevet Other Brevet Bac +5 Bac +3 Bac +5 Bac +5
[8061] Brevet Other Other Other Other Brevet Brevet Other Bac +3 Brevet
[8071] Bac +5 Bac +5 Other Bac +5 Other Bac +5 Bac +5 Other Other Other
[8081] Brevet Other Brevet Brevet Bac +3 Other Brevet Bac +5 Brevet Brevet
[8091] Other Brevet Other Brevet Bac +3 Brevet Brevet Brevet Bac +5 Other
[8101] Brevet Bac +3 Other Bac +3 Brevet Bac +3 Other Bac +5 Bac +5 Bac +3
[8111] Other Brevet Brevet Bac +3 Bac +3 Bac +5 Bac +5 Other Bac +5 Bac +5
[8121] Other Brevet Bac +3 Other Bac +5 Bac +5 Brevet Other Bac +3 Other
[8131] Bac +3 Bac +3 Other Brevet Brevet Bac +5 Bac +3 Brevet Other Bac +3
[8141] Bac +3 Bac +3 Bac +5 Brevet Other Brevet Bac +3 Bac +5 Bac +3 Bac +5
[8151] Brevet Bac +3 Other Other Bac +5 Bac +5 Bac +3 Bac +3 Brevet Brevet
[8161] Other Bac +3 Bac +3 Brevet Other Brevet Other Bac +5 Other Other
[8171] Bac +5 Bac +5 Bac +5 Bac +5 Other Bac +5 Other Other Other Bac +5
[8181] Brevet Bac +3 Bac +5 Bac +5 Brevet Other Bac +5 Bac +5 Bac +5 Other
[8191] Brevet Bac +3 Brevet Bac +3 Other Bac +3 Bac +5 Brevet Bac +5 Bac +3
[8201] Bac +3 Bac +3 Brevet Brevet Brevet Bac +3 Bac +5 Brevet Bac +5 Bac +5
[8211] Brevet Other Bac +3 Bac +5 Bac +3 Brevet Other Bac +3 Brevet Other
[8221] Brevet Other Brevet Brevet Brevet Other Other Bac +5 Bac +5 Bac +5
[8231] Brevet Other Other Bac +3 Bac +5 Brevet Bac +5 Bac +3 Brevet Bac +3
[8241] Brevet Bac +3 Other Other Bac +3 Bac +5 Bac +3 Bac +5 Bac +3 Bac +3
[8251] Bac +3 Brevet Other Other Bac +5 Brevet Bac +5 Other Bac +3 Bac +3
[8261] Bac +5 Brevet Other Bac +5 Brevet Other Other Brevet Bac +5 Brevet
[8271] Bac +5 Bac +5 Brevet Other Bac +3 Brevet Bac +5 Bac +5 Other Bac +5
[8281] Bac +3 Other Bac +3 Brevet Brevet Brevet Brevet Bac +3 Brevet Bac +5
[8291] Other Other Other Bac +5 Other Other Bac +5 Bac +5 Other Bac +3
[8301] Bac +5 Bac +5 Bac +5 Bac +5 Other Brevet Bac +5 Bac +5 Bac +5 Brevet
[8311] Brevet Bac +5 Other Brevet Bac +5 Brevet Other Bac +5 Brevet Brevet
[8321] Brevet Bac +3 Bac +5 Bac +3 Other Bac +5 Bac +3 Bac +5 Brevet Brevet
[8331] Bac +5 Other Bac +3 Bac +3 Other Other Bac +5 Brevet Bac +3 Brevet
[8341] Other Bac +3 Brevet Other Other Brevet Other Bac +3 Bac +5 Bac +5
[8351] Other Brevet Other Other Bac +5 Bac +3 Brevet Bac +5 Bac +5 Other
[8361] Brevet Brevet Bac +5 Bac +3 Bac +5 Bac +5 Brevet Bac +3 Bac +5 Other
[8371] Bac +5 Brevet Brevet Brevet Brevet Brevet Bac +5 Bac +5 Bac +5 Brevet
[8381] Bac +5 Bac +5 Bac +3 Bac +3 Bac +5 Other Bac +3 Bac +5 Brevet Other
[8391] Other Bac +5 Other Other Bac +3 Bac +5 Bac +5 Brevet Other Bac +3
[8401] Brevet Bac +5 Bac +3 Other Bac +5 Brevet Bac +3 Brevet Other Bac +3
[8411] Brevet Bac +5 Bac +5 Other Bac +3 Brevet Bac +5 Bac +5 Bac +3 Other
[8421] Bac +3 Other Brevet Bac +5 Bac +3 Bac +5 Bac +3 Brevet Bac +3 Bac +5
[8431] Bac +5 Other Bac +5 Brevet Bac +5 Brevet Bac +3 Bac +3 Other Bac +5
[8441] Bac +3 Bac +3 Bac +3 Brevet Bac +3 Brevet Bac +5 Bac +5 Other Bac +3
[8451] Other Bac +3 Bac +3 Bac +5 Brevet Bac +3 Bac +3 Brevet Bac +5 Other
[8461] Brevet Brevet Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Bac +5 Bac +3 Bac +3
[8471] Bac +5 Bac +5 Other Brevet Bac +5 Bac +5 Brevet Bac +3 Bac +5 Other
[8481] Bac +5 Brevet Bac +5 Bac +3 Bac +3 Other Bac +3 Other Bac +5 Other
[8491] Brevet Bac +3 Brevet Bac +3 Bac +5 Brevet Bac +3 Bac +3 Bac +5 Brevet
[8501] Brevet Bac +3 Bac +5 Other Bac +3 Bac +5 Other Bac +5 Other Other
[8511] Brevet Other Brevet Bac +5 Bac +5 Bac +5 Bac +5 Brevet Bac +5 Bac +3
[8521] Brevet Other Other Bac +5 Bac +5 Other Bac +3 Other Other Other
[8531] Bac +5 Other Bac +5 Bac +5 Brevet Bac +3 Brevet Other Bac +3 Bac +3
[8541] Other Other Other Bac +3 Other Bac +3 Bac +3 Bac +3 Bac +3 Bac +3
[8551] Bac +5 Bac +5 Brevet Other Bac +5 Brevet Bac +5 Other Bac +5 Bac +5
[8561] Other Other Bac +3 Bac +3 Other Bac +3 Bac +5 Other Bac +5 Bac +3
[8571] Bac +5 Bac +3 Other Brevet Bac +3 Other Bac +3 Brevet Other Other
[8581] Other Brevet Bac +5 Bac +3 Brevet Other Bac +5 Other Bac +3 Other
[8591] Bac +5 Bac +3 Bac +5 Brevet Bac +3 Brevet Bac +3 Bac +5 Bac +3 Bac +5
[8601] Bac +5 Brevet Other Bac +3 Other Bac +3 Bac +5 Brevet Bac +3 Brevet
[8611] Bac +5 Bac +5 Other Bac +5 Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Bac +3
[8621] Other Bac +3 Other Bac +3 Other Brevet Bac +3 Bac +3 Bac +5 Other
[8631] Other Bac +3 Brevet Brevet Other Bac +3 Bac +5 Other Other Bac +5
[8641] Other Brevet Bac +3 Brevet Brevet Bac +3 Bac +5 Bac +3 Other Bac +5
[8651] Bac +3 Brevet Bac +3 Brevet Bac +5 Brevet Other Bac +3 Bac +5 Bac +5
[8661] Brevet Bac +3 Bac +5 Other Bac +3 Bac +3 Bac +5 Bac +5 Other Bac +5
[8671] Bac +5 Bac +5 Bac +3 Bac +5 Bac +3 Other Other Bac +3 Other Other
[8681] Other Bac +5 Bac +3 Brevet Other Bac +3 Brevet Brevet Brevet Bac +3
[8691] Bac +5 Other Brevet Other Bac +3 Bac +5 Other Brevet Bac +3 Bac +3
[8701] Brevet Bac +5 Brevet Brevet Other Bac +5 Bac +5 Bac +3 Bac +3 Other
[8711] Bac +5 Brevet Bac +3 Brevet Bac +3 Bac +3 Other Brevet Bac +5 Other
[8721] Bac +3 Bac +3 Brevet Other Other Bac +3 Bac +5 Bac +5 Brevet Bac +3
[8731] Other Bac +3 Other Bac +5 Bac +5 Brevet Bac +5 Bac +3 Brevet Other
[8741] Bac +5 Other Bac +3 Bac +3 Bac +5 Brevet Bac +3 Bac +5 Other Bac +3
[8751] Brevet Brevet Other Bac +5 Brevet Other Bac +5 Brevet Bac +3 Brevet
[8761] Brevet Bac +5 Bac +5 Bac +3 Bac +3 Other Brevet Other Brevet Bac +5
[8771] Other Bac +3 Bac +3 Brevet Bac +3 Brevet Brevet Brevet Bac +3 Bac +3
[8781] Bac +5 Bac +5 Bac +3 Other Bac +5 Brevet Brevet Bac +5 Bac +3 Bac +3
[8791] Brevet Bac +5 Brevet Other Bac +5 Bac +5 Brevet Bac +5 Bac +5 Other
[8801] Bac +5 Bac +5 Bac +3 Brevet Bac +3 Other Brevet Bac +3 Other Other
[8811] Brevet Other Brevet Bac +5 Brevet Bac +3 Bac +5 Brevet Other Other
[8821] Bac +3 Bac +3 Brevet Bac +5 Brevet Bac +3 Brevet Other Bac +3 Brevet
[8831] Brevet Bac +5 Other Bac +3 Other Bac +5 Bac +3 Bac +3 Bac +5 Bac +5
[8841] Brevet Bac +5 Brevet Brevet Bac +3 Other Bac +5 Bac +5 Bac +3 Brevet
[8851] Bac +3 Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Bac +3 Brevet Bac +3 Bac +3
[8861] Bac +5 Other Bac +5 Brevet Other Brevet Bac +5 Other Bac +5 Bac +5
[8871] Bac +5 Brevet Bac +5 Other Bac +5 Brevet Bac +3 Bac +3 Bac +5 Other
[8881] Bac +5 Brevet Bac +5 Bac +5 Other Other Other Other Bac +5 Bac +3
[8891] Brevet Bac +3 Bac +5 Bac +5 Brevet Other Brevet Brevet Brevet Other
[8901] Other Other Bac +5 Bac +3 Brevet Bac +5 Other Brevet Bac +5 Bac +5
[8911] Bac +3 Other Other Bac +5 Brevet Other Bac +5 Bac +3 Other Bac +3
[8921] Bac +3 Bac +5 Bac +5 Bac +3 Brevet Other Other Bac +3 Bac +3 Brevet
[8931] Bac +3 Other Bac +5 Other Other Bac +3 Other Bac +3 Other Bac +5
[8941] Bac +5 Bac +3 Brevet Other Bac +3 Bac +3 Bac +5 Bac +3 Bac +5 Bac +3
[8951] Brevet Bac +3 Other Bac +5 Brevet Bac +5 Other Other Bac +3 Brevet
[8961] Bac +5 Bac +3 Brevet Bac +3 Brevet Other Brevet Bac +3 Bac +5 Bac +5
[8971] Brevet Bac +5 Brevet Other Bac +5 Other Other Other Bac +3 Other
[8981] Bac +5 Bac +5 Bac +5 Brevet Other Bac +3 Other Bac +5 Brevet Bac +3
[8991] Brevet Bac +3 Brevet Bac +3 Other Bac +5 Bac +5 Other Bac +5 Bac +5
[9001] Other Bac +3 Other Bac +5 Brevet Bac +5 Other Other Brevet Bac +5
[9011] Other Bac +5 Brevet Bac +3 Bac +5 Brevet Brevet Bac +5 Bac +5 Bac +3
[9021] Brevet Brevet Brevet Other Bac +3 Bac +3 Bac +5 Bac +5 Bac +3 Bac +5
[9031] Bac +5 Bac +3 Brevet Bac +5 Bac +5 Other Bac +3 Bac +3 Bac +3 Bac +5
[9041] Brevet Other Bac +5 Bac +3 Brevet Brevet Other Brevet Bac +3 Other
[9051] Bac +3 Brevet Other Bac +3 Bac +5 Bac +3 Bac +5 Bac +3 Bac +3 Bac +3
[9061] Bac +3 Bac +3 Bac +3 Other Bac +5 Other Bac +5 Bac +5 Brevet Bac +5
[9071] Bac +5 Bac +5 Bac +3 Other Brevet Bac +5 Bac +3 Brevet Brevet Other
[9081] Other Bac +5 Bac +5 Bac +3 Other Brevet Brevet Brevet Other Brevet
[9091] Brevet Bac +5 Bac +5 Other Bac +3 Bac +5 Other Brevet Other Bac +5
[9101] Brevet Bac +5 Other Other Bac +3 Bac +5 Bac +5 Brevet Bac +5 Other
[9111] Other Other Other Bac +5 Bac +3 Bac +3 Bac +5 Other Bac +5 Brevet
[9121] Other Bac +3 Bac +5 Other Brevet Other Other Bac +5 Brevet Brevet
[9131] Brevet Brevet Bac +3 Bac +5 Bac +3 Brevet Other Brevet Bac +3 Brevet
[9141] Other Brevet Brevet Other Brevet Other Brevet Bac +3 Bac +3 Brevet
[9151] Bac +3 Other Bac +3 Bac +3 Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +5
[9161] Brevet Other Brevet Bac +5 Brevet Bac +5 Bac +3 Bac +3 Bac +3 Brevet
[9171] Other Bac +5 Bac +5 Other Bac +5 Other Other Brevet Other Other
[9181] Bac +3 Other Bac +5 Other Bac +5 Bac +3 Bac +5 Bac +5 Bac +5 Bac +5
[9191] Other Brevet Other Brevet Bac +3 Bac +3 Other Bac +5 Brevet Other
[9201] Bac +3 Other Brevet Bac +5 Other Brevet Bac +5 Bac +3 Other Brevet
[9211] Bac +3 Bac +3 Bac +5 Bac +5 Bac +3 Bac +5 Bac +5 Brevet Bac +3 Bac +3
[9221] Bac +3 Brevet Other Other Bac +3 Bac +5 Other Brevet Other Bac +5
[9231] Bac +3 Bac +5 Bac +5 Bac +3 Brevet Brevet Brevet Bac +3 Bac +3 Other
[9241] Bac +3 Other Brevet Bac +5 Brevet Bac +3 Bac +3 Bac +3 Bac +3 Bac +3
[9251] Brevet Brevet Bac +3 Other Bac +5 Bac +3 Brevet Bac +5 Bac +3 Other
[9261] Bac +3 Brevet Brevet Other Bac +3 Other Brevet Bac +5 Other Bac +5
[9271] Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Other Bac +5 Bac +3 Other Other
[9281] Bac +3 Brevet Bac +3 Other Bac +5 Bac +5 Brevet Bac +3 Bac +5 Other
[9291] Brevet Brevet Bac +3 Bac +5 Bac +3 Bac +3 Brevet Bac +3 Bac +5 Bac +5
[9301] Brevet Brevet Bac +3 Bac +3 Brevet Brevet Other Other Bac +3 Brevet
[9311] Bac +5 Other Brevet Brevet Brevet Bac +5 Other Bac +3 Bac +5 Bac +3
[9321] Bac +5 Bac +3 Brevet Other Other Other Bac +5 Brevet Brevet Bac +3
[9331] Brevet Other Brevet Bac +5 Bac +5 Bac +3 Brevet Bac +5 Brevet Bac +5
[9341] Bac +3 Bac +3 Brevet Bac +3 Bac +5 Bac +3 Bac +5 Bac +5 Bac +5 Bac +3
[9351] Brevet Bac +3 Bac +3 Bac +3 Bac +3 Brevet Bac +3 Bac +3 Bac +3 Brevet
[9361] Brevet Bac +5 Other Brevet Bac +5 Bac +5 Bac +5 Bac +5 Other Bac +3
[9371] Bac +3 Brevet Other Bac +5 Bac +3 Bac +5 Bac +3 Bac +3 Brevet Other
[9381] Other Bac +5 Bac +3 Other Brevet Bac +5 Bac +3 Bac +5 Brevet Bac +5
[9391] Bac +5 Bac +3 Brevet Bac +5 Bac +3 Bac +5 Bac +3 Other Bac +3 Bac +5
[9401] Bac +3 Bac +5 Bac +3 Brevet Bac +5 Bac +3 Other Other Bac +3 Other
[9411] Other Brevet Bac +3 Other Bac +5 Other Bac +3 Brevet Brevet Bac +5
[9421] Bac +3 Brevet Other Other Bac +5 Brevet Brevet Other Bac +5 Bac +5
[9431] Brevet Other Brevet Bac +5 Brevet Bac +5 Bac +3 Brevet Bac +5 Bac +3
[9441] Brevet Brevet Bac +3 Brevet Brevet Other Bac +5 Other Bac +5 Brevet
[9451] Brevet Brevet Brevet Bac +5 Bac +5 Other Bac +5 Brevet Bac +5 Bac +5
[9461] Brevet Bac +5 Brevet Brevet Other Bac +3 Bac +3 Bac +5 Brevet Bac +5
[9471] Brevet Bac +3 Bac +5 Bac +3 Bac +3 Brevet Brevet Bac +3 Bac +3 Brevet
[9481] Other Bac +5 Other Bac +3 Other Bac +5 Bac +5 Bac +5 Bac +3 Bac +5
[9491] Bac +5 Bac +5 Bac +3 Bac +3 Brevet Bac +5 Brevet Brevet Other Brevet
[9501] Brevet Bac +3 Other Bac +5 Other Other Bac +3 Other Brevet Bac +3
[9511] Bac +3 Bac +5 Bac +3 Bac +3 Bac +5 Brevet Brevet Bac +3 Brevet Other
[9521] Brevet Brevet Bac +5 Brevet Bac +3 Bac +3 Bac +3 Brevet Bac +3 Brevet
[9531] Bac +3 Bac +3 Bac +5 Bac +5 Bac +3 Brevet Brevet Brevet Bac +5 Other
[9541] Other Bac +5 Bac +3 Bac +3 Bac +3 Bac +5 Bac +3 Brevet Brevet Bac +3
[9551] Brevet Other Brevet Bac +5 Other Brevet Bac +5 Brevet Bac +5 Other
[9561] Bac +3 Bac +5 Bac +5 Other Brevet Brevet Other Other Other Bac +3
[9571] Bac +3 Other Bac +3 Other Brevet Brevet Other Other Bac +3 Bac +5
[9581] Other Other Bac +5 Other Other Brevet Brevet Brevet Other Bac +5
[9591] Bac +5 Bac +3 Bac +3 Other Brevet Other Bac +3 Brevet Brevet Bac +5
[9601] Brevet Other Other Bac +5 Bac +3 Other Other Bac +5 Bac +3 Other
[9611] Bac +3 Brevet Brevet Bac +3 Bac +5 Other Other Other Bac +3 Brevet
[9621] Brevet Bac +3 Other Other Other Brevet Brevet Bac +3 Other Other
[9631] Bac +3 Bac +3 Bac +5 Brevet Other Other Brevet Bac +5 Other Bac +3
[9641] Brevet Other Bac +3 Bac +5 Bac +5 Bac +5 Bac +5 Bac +3 Bac +3 Bac +5
[9651] Bac +3 Bac +3 Other Brevet Other Other Brevet Brevet Bac +5 Other
[9661] Bac +3 Brevet Bac +3 Other Bac +3 Brevet Bac +3 Brevet Other Other
[9671] Brevet Brevet Bac +5 Brevet Bac +3 Brevet Bac +3 Other Bac +5 Brevet
[9681] Brevet Brevet Other Bac +3 Brevet Bac +3 Brevet Other Bac +3 Other
[9691] Bac +5 Bac +3 Bac +5 Other Bac +3 Bac +5 Brevet Other Other Brevet
[9701] Brevet Bac +5 Bac +3 Brevet Brevet Bac +3 Other Other Brevet Bac +3
[9711] Brevet Bac +3 Other Other Bac +3 Brevet Other Brevet Other Other
[9721] Other Brevet Other Bac +5 Bac +5 Brevet Bac +5 Bac +5 Brevet Brevet
[9731] Bac +5 Other Other Brevet Bac +3 Bac +3 Bac +5 Bac +3 Other Brevet
[9741] Brevet Brevet Brevet Brevet Other Other Brevet Brevet Brevet Brevet
[9751] Other Other Other Bac +3 Bac +5 Bac +3 Bac +3 Other Bac +3 Brevet
[9761] Bac +5 Brevet Brevet Bac +5 Brevet Other Brevet Brevet Other Bac +5
[9771] Bac +3 Brevet Other Bac +3 Bac +5 Brevet Bac +5 Brevet Bac +3 Brevet
[9781] Brevet Other Other Bac +3 Bac +3 Bac +5 Brevet Other Other Brevet
[9791] Other Bac +5 Bac +3 Other Brevet Other Brevet Other Brevet Bac +3
[9801] Bac +5 Bac +3 Bac +3 Brevet Bac +3 Brevet Brevet Brevet Bac +3 Bac +5
[9811] Bac +3 Brevet Brevet Brevet Brevet Brevet Brevet Brevet Other Bac +3
[9821] Other Bac +3 Bac +3 Other Brevet Other Bac +3 Other Brevet Bac +3
[9831] Other Bac +5 Other Bac +3 Bac +5 Other Brevet Bac +5 Bac +5 Bac +3
[9841] Bac +3 Bac +3 Brevet Other Bac +3 Other Bac +5 Bac +3 Other Other
[9851] Brevet Other Brevet Brevet Brevet Bac +5 Brevet Bac +3 Bac +3 Bac +5
[9861] Bac +5 Brevet Brevet Bac +5 Bac +5 Other Bac +3 Bac +3 Other Bac +5
[9871] Brevet Bac +3 Bac +3 Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +5 Bac +5
[9881] Bac +3 Bac +5 Other Other Bac +3 Bac +3 Brevet Bac +5 Bac +3 Other
[9891] Bac +5 Brevet Bac +3 Bac +3 Bac +5 Bac +3 Brevet Brevet Bac +3 Brevet
[9901] Other Brevet Bac +5 Bac +3 Bac +5 Bac +5 Brevet Bac +5 Bac +3 Bac +3
[9911] Bac +5 Bac +5 Bac +5 Bac +3 Brevet Bac +5 Brevet Other Bac +5 Brevet
[9921] Bac +3 Other Other Bac +3 Bac +5 Bac +3 Other Brevet Bac +5 Brevet
[9931] Bac +3 Brevet Bac +5 Bac +3 Other Bac +3 Bac +5 Bac +5 Other Other
[9941] Bac +5 Other Other Bac +5 Bac +5 Brevet Bac +5 Bac +3 Bac +3 Other
[9951] Other Other Bac +3 Bac +5 Bac +5 Brevet Brevet Bac +5 Other Other
[9961] Bac +5 Bac +5 Other Bac +3 Bac +5 Bac +5 Bac +5 Brevet Bac +5 Bac +3
[9971] Other Bac +5 Brevet Other Brevet Bac +5 Brevet Brevet Bac +5 Other
[9981] Bac +5 Brevet Other Brevet Bac +3 Bac +5 Brevet Bac +3 Bac +5 Bac +3
[9991] Brevet Brevet Other Other Bac +3 Brevet Brevet Bac +5 Bac +3 Bac +5
Levels: Bac +3 Bac +5 Brevet Other
La différence de mémoire utilisée est donc égale à 39 584 bytes.
15.22 Vectorisation
Améliorer son code
Formation expertise
En R, les boucles sont des opérations plutôt lentes. Il est cependant possible, dans de nombreux cas, d’éviter de les employer, en ayant recours à la vectorisation : au lieu d’appliquer une fonction scalaire par scalaire, on l’applique directement à un vecteur.
De nombreuses fonctions sont vectorisées en R, c’est le cas des fonctions +, -, * et / par exemple.
La vectorisation rend les problèmes plus simples : au lieu de réflechir au niveau des éléments du vecteur, on se situe au niveau des vecteurs eux mêmes
Les fonctions vectorisées en R sont rédigées en C ou C++ et sont donc plus rapides
Ici, on entend par vectoriser son code trouver la fonction R implémentée en C qui s’applique le mieux à notre problème.
Les fonctions les plus couramment utilisées pour vectoriser un code sont les fonctions rowSums, colSums, rowMeans, colMeans, etc. Ces fonctions matricielles vectorisées peuvent être utilsées pour alimenter d’autres fonctions et les rendre plus rapides.
15.23 Question 9
Améliorer son code
Formation expertise
Voici un programme R permettant de calculer la somme cumulée de la population en 2016 et en 2017 sur plusieurs communes d’une même région.
Vectoriser ce code de sorte à ce qu’il soit plus performant. Quel est le gain de temps d’exécution de la fonction vectorisée par rapport à la fonction non-vectorisée ?
# Calculez la somme cumulée pour chaque variablesum_cum_pop<-function(data){nb_lignes<-nrow(data)pop_sum_cum_2016<-data[1, "population_2016"]pop_sum_cum_2017<-data[1, "population_2017"]for(iin2:nb_lignes){pop_sum_cum_2016<-pop_sum_cum_2016+data[i, "population_2016"]pop_sum_cum_2017<-pop_sum_cum_2017+data[i, "population_2017"]}return(c("population_2016"=pop_sum_cum_2016,"population_2017"=pop_sum_cum_2017))}
15.24 Correction 9
Améliorer son code
Formation expertise
# Calculez la somme cumulée pour chaque variablesum_cum_pop_vectorise<-function(data){return(colSums(data))}# Exemple de donnéesset.seed(123)data<-data.frame( population_2016 =rnorm(100, mean =50000, sd =10000), population_2017 =rnorm(100, mean =50000, sd =10000))bench::mark(sum_cum_pop(data),sum_cum_pop_vectorise(data))[c("expression", "min", "median", "itr/sec", "n_gc")]
Le temps d’éxecution est bien moindre pour la fonction vectorisée que pour la boucle for.
15.25 Question 10
Améliorer son code
Formation expertise
Selon une idée reçue, utiliser les fonctions de type apply ou purrr::map serait plus efficace que d’utiliser des boucles. Il serait alors possible d’améliorer la performance en accélérant l’éxecution d’une liste de tâches répétitives à l’aide d’une plus grande puissance de calcul.
On propose de vérifier cette affirmation.
On considère la liste de vecteurs suivante :
vecteurs<-lapply(1:10^5, function(i)runif(100))# La fonction runif génère des valeurs aléatoires suivant une distribution uniforme
Comparer le temps d’exécution en utilisant la fonction sapply, la fonction purrr::map_dbl et une boucle for pour obtenir la somme de chaque vecteur de la liste.
15.26 Correction 10
Améliorer son code
Formation expertise
# Utilisation d'une boucleloop_sum1<-quote({result<-c()for(iinseq_along(vecteurs)){result[i]<-sum(vecteurs[[i]])}result})loop_sum2<-quote({result<-numeric(length(vecteurs))# On initialise d'emblée la bonne taille et le bon typefor(iinseq_along(vecteurs)){result[i]<-sum(vecteurs[[i]])}result})sapply_sum<-quote({result<-sapply(vecteurs, sum)result})map_sum<-quote({result<-purrr::map_dbl(vecteurs, sum)result})bench::mark(eval(loop_sum1),eval(loop_sum2),eval(sapply_sum),eval(map_sum))
16 Justesse
16.1 Introduction
Améliorer son code
Formation expertise
Plusierts éléments permettent de résoudre les problèes de justesse :
La console affiche pendant l’exécution, un texte appelé log contenant des informations sur la bonne exécution ou non du code avec notamment la nature du bug (s’il y en a)
La documentation R d’un objet est accessible via “?”, par exemple ?data.frame explique l’utilisation générale de cet objet (utilité, syntaxe, options possibles, type de valeur en entrée et en sortie)
Internet héberge énormément de forums utilisateurs sur les langages informatiques comme R abordant des sujets divers. Il est fort probable que l’on puisse y trouver une solution aux problèmes que nous rencontrons. En particulier, le forum de questions/réponses stackoverflow se révèle généralement utile, même sans poser soi-même les questions car souvent d’autres personnes ont déjà rencontré le même problème
Un collègue plus expérimenté ou ayant déjà rencontré ce problème sera certainement à même d’apporter une solution. Toutefois, il est préférable d’en solliciter un uniquement si aucune solution n’a pu être trouvée par les moyens cités plus haut dans des délais raisonnables
Néanmoins, il existe d’autres outils plus avancés permettant de mieux comprendre les erreurs pour les résoudre plus efficacement que nous présentons dans cette partie.
16.3 Breakpoints et menu Debug
Améliorer son code
Formation expertise
Il est possible d’ajouter des breakpoints pour inspecter le code au niveau de certaines lignes, directement grâce à l’IDE RStudio.
Le breakpoint permet d’indiquer une ligne à laquelle on souhaite inspecter l’état des objets pour débugger une fonction ou une boucle. Le breakpoint permet d’arrêter automatiquement l’exécution du code à la ligne indiquée et d’ouvrir une fenêtre d’inspection de l’état des variables en cours. On inspecte ensuite l’évolution des objets au fil des itérations d’une boucle ou d’une fonction en évitant dd’interrompre l’exécution à chaque itération.
Il est également possible de mettre plusieurs breakpoints à la suite et ainsi exécuter le code bout par bout.
16.4 Comment associer une ligne de code à un Breakpoint ?
Améliorer son code
Formation expertise
Soit directement en cliquant à côté du numéro de la ligne ;
Soit dans Debug > Toggle Breakpoint une fois le curseur sur la bonne ligne.
16.5 Breakpoint (suite)
Améliorer son code
Formation expertise
NB : Il faut s’assurer que “On Error” est bien sur “Error inspector” ou “Break in code” :
On exécute ensuite le code à l’aide de “Run”, ou de “Source” (ou en pressant Ctrl + Shift + S).
Les commandes de base dans le mode de débugging sont les suivantes :
n : Exécute la prochaine ligne de code.
c : Continue l’exécution jusqu’à ce qu’une autre occurrence de browser() soit atteinte (cf. Fonction browser).
q : Quitte le mode de débugging et termine l’exécution de la fonction en cours.
16.6 Breakpoint (suite)
Améliorer son code
Formation expertise
Elles sont présentées dans l’onglet Debug. Elles apparaissent également dans la console.
L’onglet Environnement se met à jour et permet d’inspecter les objets appelés dans la fonction ou la boucle que l’on souhaite débugger.
En appuyant sur Entrée, on avance dans l’exécution de la boucle ou de la fonction et les valeurs des objets évoluent en fonction.
16.7 Breakpoint (suite)
Améliorer son code
Formation expertise
L’onglet Environnement permet aussi de détailler le Traceback (ou Call stack), qui détaille tous les appels à la mémoire vive du code inspecté.
Par exemple ici, la fonction f est une résultante d’appel aux fonctions g, h, et i.
16.8 Question 11
Améliorer son code
Formation expertise
On considère le code suivant avec deux fonctions emboîtées :
En utilisant un ou plusieurs breakpoints, debugger les fonctions pour ne plus avoir un résultat égal à “Inf” (on peut par exemple passer les opérations conduisant à ce résultat ou bien les remplacer par autre chose).
16.9 Correction 11
Améliorer son code
Formation expertise
On commence par placer un breakpoint au niveau de la ligne return(final_result) de la fonction outer_function. On se rend compte que c’est à cause de la variable x que final_result vaut “Inf”.
Le problème vient donc de l’appel à la fonction inner_function. On place alors un autre breakpoint au niveau de result <- result + z pour inspecter les objects à chaque itération de la boucle de la fonction. On se rend compte que result vaut Inf à partir de la 3ème itération, car z vaut Inf. Cela est du au fait que l’on divise par vec2[3] qui vaut 0.
16.10 Correction 11
Améliorer son code
Formation expertise
Voici une proposition de correction de la question pour empêcher ce problème :
inner_function<-function(vec1, vec2){result<-0for(iin1:length(vec1)){# On ajoute une condition pour passer le cas où on divise par zéroif(vec2[i]==0){next}z<-vec1[i]/vec2[i]result<-result+z}return(result)}outer_function<-function(vec1, vec2, y){x<-inner_function(vec1, vec2)final_result<-x*yreturn(final_result)}result<-outer_function(c(1, 2, 3, 4), c(1, 5, 0, 6), 5)
16.11 Fonction debug
Améliorer son code
Formation expertise
Alternativement aux breakpoints, on peut utiliser la fonction debug qui permet d’activer le mode debug lorsqu’une fonction est appelée.
debug(outer_function)# Active le mode debug lorsque la fonction sera appeléeresult<-outer_function(c(1, 2, 3, 4), c(1, 5, 0, 6), 5)undebug(outer_function)# Retire le mode debug# Alternativementdebugonce(outer_function)# Active le mode debug uniquement pour le prochain appelresult<-outer_function(c(1, 2, 3, 4), c(1, 5, 0, 6), 5)
16.12 Fonction browser
Améliorer son code
Formation expertise
La fonction browser est une fonction de débugging interactive, qui permet d’arrêter l’exécution du code à un certain point et d’ouvrir une session interactive pour explorer l’environnement courant et comprendre le comportement du code. Elle est équivalente à l’ajout d’un breakpoint sur la ligne suivante.
Dans cet exemple, lorsque la fonction atteint le point d’arrêt browser(), l’exécution est suspendue. On peut alors inspecter les valeurs des variables jusqu’à relancer l’exécution.
ma_fonction<-function(x){y<-x*2browser()# Point d'arrêtz<-y+5return(z)}# Appel de la fonctionresult<-ma_fonction(3)
Called from: ma_fonction(3)
debug: z <- y + 5
debug: return(z)
En utilisant la fonction browser(), trouver la valeur de carre_recursif(2, 2) sans lancer la commande carre_recursif(2, 2).
16.14 Correction 12
Améliorer son code
Formation expertise
On commence par placer une fonction browser() à la fin de chaque itération. Puis, en exécutant le code de la fonction carre_recursif(2, 5), on peut observer la valeur de resultat à chaque itération. On cherche alors la valeur de resultat lorsque itérations est égale à 2.
carre_recursif<-function(base, iterations){if(iterations==0){return(base)}else{resultat<-base^2browser()# Point d'arrêtreturn(carre_recursif(resultat, iterations-1))}}resultat<-carre_recursif(2, 5)
On trouve alors que carre_recursif(2, 2) est égale à 16, ce que l’on peut vérifier en exécutant la commande :
resultat<-carre_recursif(2, 2)
resultat
[1] 16
17 Robustesse
17.1 Introduction
Améliorer son code
Formation expertise
La robustesse consiste à s’assurer que le code fonctionne de manière fiable, y compris face à une variabilité de la situation (par exemple pouvoir fonctionner avec une table avec un nombre de lignes différents).
Être capable de détecter et gérer les erreurs peut être un moyen d’améliorer la robustesse d’un code.
17.2 Assurer l’exécution du code en gérant les erreurs
Améliorer son code
Formation expertise
Parfois, il est essentiel d’assurer qu’un code s’exécute sans générer d’erreur. Il est alors possible de capturer les erreurs pour pouvoir continuer à exécuter le reste.
Nous pouvons par exemple utiliser la fonction purrr::safely qui permet de transformer une fonction de sorte qu’elle s’exécute toujours sans erreur. Si une erreur devrait survenir alors elle est retournée sans interrompre la suite du code.
$result
NULL
$error
<simpleError in x + y: non-numeric argument to binary operator>
17.3 Capturer manuellement les erreurs avec tryCatch
Améliorer son code
Formation expertise
Comme vu en approfondissement de la formation Consolidation, on peut utiliser la fonction tryCatch lorsque l’on prévoit à l’avance qu’une erreur est susceptible de se produire et que l’on souhaite définir une action à faire le cas échéant.
La fonction tryCatch qui va essayer d’exécuter un code et qui permet d’en exécuter un autre en cas d’erreur.
custom_add<-function(x, y){tryCatch(x+y, error =function(e){message("Il y a eu une erreur : concaténation utilisée à la place")message(e)paste0(x, y)})}custom_add(1, 2)
[1] 3
custom_add(1, "a")
Error in x + y: non-numeric argument to binary operator
17.4 Capturer manuellement les erreurs avec tryCatch
Améliorer son code
Formation expertise
Dans l’exemple ci-dessus, l’addition n’est possible que si les 2 paramètres renseignés sont des nombres. Si l’un des paramètres est d’un type différent, une erreur sera produite. Pour éviter cela, la fonction tryCatch est utilisée. Le code suivant revient à dire, si les deux paramètres sont des entiers alors additionner normalement, dans le cas contraire, envoyer un message prévenant que l’addition n’est pas possible et à la place, réaliser une concaténation.
Note
tryCatch permet également de prévoir des actions en cas de Warning et/ou de prévoir des actions à exécuter à la fin, qu’il y ait eu une erreur (ou warning) ou non. La documentation et ce post sur stackoverflow fournissent davantage de détails.
17.5 Question 13
Améliorer son code
Formation expertise
À l’aide de tryCatch et d’une boucle afficher le double de chaque élément de list(1, 2, "a", 4), ou NA en cas d’erreur.
tryCatch peut être combiné avec break et next qui permettent respectivement d’arrêter une boucle et de passer à l’itération suivante. Cela permet une flexibilité dans la gestion des boucles.
17.7 Question 14
Améliorer son code
Formation expertise
À l’aide de tryCatch et d’une boucle afficher le double de chaque élément de list(1, 2, "a", 4) jusqu’à ce qu’une erreur survient, auquel cas on arrête la boucle.
*Note : tryCatch peut renvoyer l’erreur et on peut ensuite vérifié si l’objet renvoyé est une erreur via inherits(y, "error").
La manipulation des chaînes de caractères soulève très vite la question de la robustesse du code. En effet, avec les chaînes de caractères, les cas possibles à anticiper sont très nombreux (fautes de frappe, majuscules vs minuscules, …).
Les expressions régulières permettent de répondre à cette problématique et sont aujourd’hui beaucoup utilisées à des fins d’analyses textuelles. Cette notion est abordée en Séquence 3 de la formation Consolidation et une section d’UtilitR y est dédiée.
Les possibilités offertes par les expressions régulières sont très nombreuses, la syntaxe associée est donc très riche, d’où le focus sur ce sujet.
Les notions abordées seront illustrées par des traitements réalisés sur la colonne telephone de la table revenus.
17.10 Principe
Améliorer son code
Formation expertise
Une expression régulière - également appelée regex (de l’anglais regular expression) - correspond à une chaîne de caratère décrivant, selon une syntaxe précise, un ensemble de chaînes de caractères possibles correspondant (i.e. “match”) à cette même syntaxe. Les expressions régulières sont représentées par un ensemble de symboles constituant le motif dénottant les chaînes de caractères décrites. L’une des principales forces des regex est l’existence de standards permettant d’assurer une certaine cohérence. Si des différences peuvent parfois exister, la plupart des langages de programmation utilisent les mêmes principaux opérateurs pour décrire des expressions régulières.
Parmi les symboles utilisés, il faut différencier les symboles dotés d’une sémantique particulière, appelés opérateurs (ex : ?,*, |, +, …), et les symboles, dits littéraux, ne réprésentant qu’eux-mêmes (ex : a, B, 8, …).
17.11 Principe
Améliorer son code
Formation expertise
Elles permettent notamment d’effectuer des recherches de texte dans un document ou une table, où le regex décrit les propriétés communes des chaînes de caractères recherchées. Ces recherches permettent alors d’opérer automatiquement certaines opérations :
Extraire les mots commençant par une majuscule dans une phrase ou un document
Extraire du texte correspondant à un format de date particulier
Effectuer des transformations sur des cellules commmençant ou terminant par un mot en particulier
Extraire un nombre d’une cellule textuelle
On peut par exemple détecter une date de la façon suivante :
library(stringr)textes<-c("14/07/1789", "J'ai 11 ans.", "R 4.3.3 a été déployé le 29/02/2024")str_detect(string =textes, pattern =r"(\d{2}/\d{2}/\d{4})")# On cherche 2 chiffres puis "/" puis 2 chiffres puis "/" puis 4 chiffres
[1] TRUE FALSE TRUE
La syntaxe r"(...)" permet de définir un “raw string” c’est à dire que le texte est à lire littéralement sans chercher à convertir les caractères spéciaux. Cette syntaxe est particulièrement utile en travaillant avec des expressions régulières.
17.12 A savoir : Aide sur les regex
Améliorer son code
Formation expertise
Il existe des sites spécialisés qui permettent de tester les regex détaillant chaque élément des expressions, par exemple https://regex101.com/.
De plus, les IA génératives comme chatGPT sont plutôt performantes pour générer ou expliquer des expressions régulières. Il faut toutefois être vigilant avec ces outils et bien vérifier le résultat :
Par exemple, dans le cas ci-dessus, la regex fournie pattern <- "\\b[iI]-?p(a|hone|ad)\\s*\\d+\\b" traite la possibilité de majuscule pour le “I” mais pas pour le “P”. De plus la conclusion est à moitié fausse car la regex ne détectera pas “ip-7” par exemple.
17.13 Répétitions
Améliorer son code
Formation expertise
Les répétitions peuvent être indiquées via
+ : une ou plusieurs occurences
* : n’importe quel nombre d’occurences, y compris zéro
? : zéro ou une occurrence
{n}, {n,}, {,n} ou {n, p} : n occurrences, au moins n occurrences, au plus n occurrences ou entre n et p occurences
On peut utiliser des parenthèses pour créer un groupe, qui peut être répété par exemple.
Si l’on souhaite indiquer comme caractère littéral un des symboles spéciaux ?,+,*,.,|,[,],(,), …, alors ils doivent être référencés dans une séquence d’échappement en les précédant du caractère \. Par exemple, dans un regex, le caractère + est recherché avec l’expression \+.
Attention, les regex sont décrits avec des chaînes de caractères. Or, R utilise également \ comme caractère d’échappement pour signaler les caractères spéciaux (par exemple, \n pour revenir à la ligne).
Ainsi, en R, l’échappement des caractères spéciaux dans un regex se fera à l’aide de deux symboles \ ou bien à l’aide de raw strings. Par exemple, dans un regex en R, le caractère + est recherché avec l’expression "\\+" ou bien r"(\+)".
Parfois, le recours à l’échappement peut rapidement devenir déroutant du fait de la multiplication des \. On peut alors avoir recours au format raw string pour ne pas interpréter ce symbole comme un symbole d’échappement.
Notamment, lorsqu’on travaille avec des regex, les raw strings sont utiles afin de décrire des motifs contenant des backslashes sans avoir à les “échapper”.
17.15 Séquence d’échappement
Améliorer son code
Formation expertise
Concrètement, un raw string commence par r"( et se termine par )", on peut également utiliser r"[...] ou r"{...}", notamment quand le string contient les caractères "(.
Ci-dessous, il semblerait que nous n’observions pas de différences entre les deux écritures. Cela provient du fait que la représentation affichée d’un string par la fonction print est différente du string lui-même : en effet, l’affichage montre les échappements.
17.16 Séquence d’échappement
Améliorer son code
Formation expertise
Afin de voir le contenu brut du string, on peut utiliser la fonction str_view:
Ainsi, pour afficher un backslash, dans le premier cas il a fallu en indiquer deux, dans le second cas il a fallu en indiquer un seul.
17.17 Question 15
Améliorer son code
Formation expertise
Ecrire une regex permettant de détecter une addition de 2 nombres entiers naturels. On la testera sur les éléments suivants c("1+2", "3*4", "5 + 12", "1492")
17.18 Correction 15
Améliorer son code
Formation expertise
str_detect(c("1+2", "3*4", "5 + 12", "1492"),r"(\d+\s*\+\s*\d+)", # \s désigne toute sorte d'espace (il existe par exemple les espaces insecables))
[1] TRUE FALSE TRUE FALSE
17.19 Classes de caratères
Améliorer son code
Formation expertise
Les classes de caractères peuvent être définies soit en les énumérant (par extension) [abcd], soit négativement [^abcd].
Les classes de caractères peuvent également être définies en “intension” : par exemple, [0-9] (ou \d) est équivalent à [0123456789], [a-z] décrit l’ensemble des caractères minuscules de l’alphabet, [a-zA-Z] désigne l’ensemble des lettres minuscules et majuscules (liste non exhaustive des classes).
str_detect(c("C3PO", "R2D2", "Skywalker"),r"([A-Z0-9]{2,})", # Au moins 2 lettres majuscules ou chiffres)
[1] TRUE TRUE FALSE
17.20 Position
Améliorer son code
Formation expertise
La position peut être contrôlée via ^ et $ désignant respectivement le début et la fin d’une ligne.
str_detect(c("L'INSEE a publié une étude", "C'est une étude publiée par l'INSEE"),"INSEE$",)
[1] FALSE TRUE
Par ailleurs \b correspond au début ou à la fin d’un mot. Par exemple, l’expression \brugby\b détectera rugby dans la phrase “J’aime le rugby” mais ne le détectera pas dans la phrase “J’applaudis les rugbymen”.
Au contraire, \B sert à dénoter une expression au milieu d’un mot. Par exemple, l’expression \Bma\B détectera “ma” dans la phrase “J’aime les tomates” mais ne le détectera pas dans la phrase “ma philosophie”.
17.21 Question 16
Améliorer son code
Formation expertise
Écrire une expression régulière pour vérifier si une chaîne de caractères est un numéro de téléphone portable valide en France. Un numéro de téléphone valide en France doit commencer par “06” ou “07” suivi de 8 chiffres.
17.22 Correction 16
Améliorer son code
Formation expertise
L’expression régulière correcte est ^(06|07)[0-9]{8}$
^: Cela indique que la correspondance doit commencer au début de la chaîne. En d’autres termes, le numéro de téléphone doit commencer par “06” ou “07”.
(06|07): Les parenthèses définissent un groupe, et | est l’opérateur “OU”. Ainsi, (06|07) signifie que le numéro doit commencer par “06” ou “07”.
[0-9]: [0-9] représente un chiffre (0-9). {8} spécifie que le chiffre précédent doit apparaître exactement 8 fois.
$: Cela indique que la correspondance doit se terminer à la fin de la chaîne.
17.23 Question 17
Améliorer son code
Formation expertise
Harmoniser les éléments de la colonne telephone de la base revenus de sorte à ce que chaque élément soit au format 06XXXXXXXX (on pourra utiliser la fonction str_replace_all).
En R, on appelle pattern le motif que l’on décrit avec un regex et que l’on recherche.
Le package stringr, issu comme dplyr de l’ensemble de packages tidyverse, fournit un ensemble de fonctions pour travailler avec les formats strings. stringr interprète naturellement les patterns qui lui sont indiqués comme des regex.
Afin de détecter la présence d’un motif dans un string, il faut utiliser la fonction str_detect. Celle-ci retourne TRUE si un élément du texte sur lequel la fonction est appliquée correspond au motif indiqué.
17.26 Question 18
Améliorer son code
Formation expertise
Créer une fonction qui prend en argument une phrase de type character et qui renvoie TRUE si la phrase comporte un chiffre et FALSE sinon.
17.27 Correction 18
Améliorer son code
Formation expertise
detecter_chiffre<-function(phrase){resultat<-str_detect(phrase, "[0-9]")return(resultat)}detecter_chiffre("Aujourd'hui j'ai mangé 4 pommes et 8 bananes")
[1] TRUE
detecter_chiffre("Hier, je n'en ai pas mangé")
[1] FALSE
Il existe d’autres fonctions de détection :
str_which retourne, dans une liste de strings, les indices de ceux comprenant une correspondance.
str_locate retourne, dans une liste de strings, les positions au sein de ces strings correspondant à la première correspondance (s’il y en a une, sinon la fonction renvoie NA).
Afin d’avoir les positions pour chaque correspondance, il faut utiliser str_locate_all.
str_subset retourne, dans une liste de strings, les strings (en entier) contenant une correspondance avec le pattern indiqué.
str_extract retourne, dans une liste de strings, les premières correspondances trouvées avec le pattern indiqué pour chaque string.
str_extract_all retourne, dans une liste de strings, toutes les correspondances trouvées avec le pattern indiqué pour chaque string.
str_match est analogue à str_extract, à la différence que les correspondances sont retournées dans dans une matrice au lieu d’un vecteur.
str_match_all est analogue à str_extract_all, à la différence que les correspondances sont retournées dans dans une liste de matrices au lieu d’une liste de vecteurs.
17.29 Question 19
Améliorer son code
Formation expertise
Extraire les noms propres du texte suivant
phrase<-"Louis et Martin sont allés à Madrid alors qu'ils souhaitaient visiter la Pologne"
Indices :
Cela revient à trouver une lettre majuscule seule suivie par au moins une lettre minuscule ou majuscule, le tout suivi par n’importe quel nombre d’espaces
En regex, les espaces sont dénotés par \s
Attention à la règle d’échappemment des symboles spéciaux en R !
17.30 Correction 19
Améliorer son code
Formation expertise
Voici deux méthodes qui nous permettent d’obtenir le résultat :
str_replace retourne, dans une liste de strings, la liste de ces mêmes strings mais dont les premières correspondances trouvées avec le pattern indiqué sont remplacées par le string indiqué en argument (argument replacement).
str_replace_all retourne, dans une liste de strings, la liste de ces mêmes strings mais dont toutes les correspondances trouvées avec le pattern indiqué sont remplacées par le string indiqué en argument (argument replacement).
18 Quiz
18.1 Question 1
Améliorer son code
Formation expertise
Quel est le format de variable le plus efficace pour une variable pouvant prendre deux valeurs différentes ?
A) Des booléens
B) Des facteurs
C) Des chaînes de caractères
18.2 Correction 1
Améliorer son code
Formation expertise
La réponse correcte est la réponse :
A) Des booléens
18.3 Question 2
Améliorer son code
Formation expertise
Quelle expression régulière permet de vérifier si une chaîne de caractères est un numéro de téléphone portable valide en France ? Un numéro de téléphone valide en France doit commencer par “06” ou “07” suivi de 8 chiffres.
A)^(06|07)\c{8}$
B)^(0|9)[6-7]{8}$
C)^(06|07)[0-9]{8}$
18.4 Correction 2
Améliorer son code
Formation expertise
La réponse correcte est la réponse :
C)^(06|07)[0-9]{8}$
18.5 Question 3
Améliorer son code
Formation expertise
Quel outil permet de débugger un code en identifiant une ligne de code précise ?
Cette séquence a pour but de permettre aux stagiaires d’être à l’aise avec les notions de base relatives aux packages sur R. Les packages peuvent être utiles pour centraliser des fonctions utilisées conjointement et de manière récurrente.
Elle permet aux stagiaires :
de comprendre l’utilité des packages et les enjeux liés à leur utilisation
de connaître les étapes et commandes de base permettant de créer un package
20.2 Pourquoi développer un package ?
Les bases d’un package
Formation expertise
L’utilisation de packages est quasiment incontournable lorsque l’on code en R. La plupart des utilisateurs se contentent d’utiliser des packages publiés par les autres mais il est possible d’écrire son propre package, ce qui peut présenter de nombreux avantages :
Organisation du code : Un package permet de structurer le code de manière logique en regroupant les fonctions, les données et la documentation associée. Cela rend le code plus lisible et plus facile à gérer.
Réutilisation : On peut réutiliser des fonctions et des données d’un package dans différents projets, ce qui fait gagner du temps et assure une cohérence dans les analyses.
Documentation : Les packages en R permettent d’inclure une documentation complète, ce qui facilite la compréhension du code pour vous-même et pour d’autres utilisateurs. Les standards de documentation comme roxygen2 simplifient cette tâche.
20.3 Pourquoi développer un package ?
Les bases d’un package
Formation expertise
Distribution et partage : Un package est un moyen idéal de partager les outils et les fonctions développés, que ce soit en interne avec ses collègues ou bien de manière ouverte. Il est possible de publier un package sur CRAN (Comprehensive R Archive Network) ou sur d’autres dépôts, ce qui permet aux autres utilisateurs de l’installer facilement.
Gestion des dépendances : Les packages en R permettent de spécifier les dépendances de votre code. Cela garantit que les utilisateurs du package ont les packages nécessaires installés et à jour.
Versioning : Les packages ont un système de version, ce qui facilite la gestion des mises à jour et la rétrocompatibilité avec d’anciennes versions du code.
Tests unitaires : Il est possible d’inclure des tests unitaires dans un package, ce qui permet de s’assurer que le code fonctionne correctement. Cela facilite également la détection de régressions lorsque des mises à jour sont apportées au code.
Performance : Le code sous forme de package peut bénéficier d’optimisations de performance, notamment en évitant le chargement inutile de données ou de fonctions.
20.4 Enjeux autour de la construction d’un package
Les bases d’un package
Formation expertise
Avant de se lancer dans la création de packages sur R, il est important de se poser plusieurs questions concernant la pertinence du développement du package et la manière dont celui-ci évoluera.
Taille : Un package doit avoir une taille appropriée. Ainsi, la création d’un package est utile si un nombre significatif de fonctions devront être réutilisées régulièrement ; en revanche, il n’est pas indispensable de créer un package contenant un nombre très limité de fonctions.
Maintenance : Il est important de se poser la question de l’utilisation du package et du besoin éventuel de mises à jour régulières. En effet, les packages se veulent généralement évolutifs, avec des mises à jour en cas de nécessité. Or, si on sait par avance qu’un package nécessitera des mises à jour mais que celles-ci pourront difficilement être effectuées (pour contrainte de disponibilité/temps par exemple), il n’est peut-être tout simplement pas pertinent de créer un package qui deviendrait rapidement obsolète.
20.5 Enjeux autour de la construction d’un package
Les bases d’un package
Formation expertise
Hébergement/diffusion : Enfin, il est important de se demander à qui le package est destiné. En effet, plusieurs utilsations sont possibles, ce qui aura un impact sur la façon d’héberger le package. Un package pourra être développé pour un usage personnel uniquement ; dans ce cas, l’hébergement du package est simplifié est peut être réalisé sur un dossier local/personnel. En revanche, un package destiné à être utilisé par un public large devra être mis à disposition de ce public à travers un hébergement adapté et permettant un accès large.
21 Création du package
21.1 Initialisation du package
Les bases d’un package
Formation expertise
La création d’un package peut se faire manuellement depuis RStudio en suivant les commandes suivantes :
Initialisation du package : File > New Project > New Directory > R package using devtools. L’initialisation ne se fait en principe qu’une fois et on ne revient ensuite pas à cette étape.
Il ne faut pas que le package se trouve à l’intérieur d’un autre projet (projet RStudio, repo Git, autre package) ou à l’intérieur d’une librairie de packages, contenant des packages déjà installés.
21.2 Question 1
Les bases d’un package
Formation expertise
Créer un package nommé inseexpert. On peut par exemple choisir de le créer dans le Home directory.
On observe alors qu’un dossier est automatiquement créé avec notamment :
Un projet .Rproj
Un sous-dossier R - C’est dans ce dossier qu’on stockera les scripts
Un fichier DESCRIPRION - C’est la carte de visite du package. On y décrit son nom, ce qu’il fait, les contributeurs, les licences etc.
Un fichier NAMESPACE - C’est un fichier décrivant les éléments exportés par les packages (par exemple des fonctions ou des données). Comme indiqué, ce fichier est généré automatiquement et ne doit pas être modifié manuellement.
Un fichier .Rbuildignore - Il liste les fichiers à ignorer au moment de la construction finale du package (“build”).
Un fichier .gitignore - Pour l’éventualité où l’on souhaite utiliser Git.
21.3 Historique : le fichier dev_history.R
Les bases d’un package
Formation expertise
Il est possible pour un utilisateur de lister toutes les étapes de création d’un package en utilisant un script R nommé dev_history.R. Cela permet de conserver manuellement un historique de développement du package, et facilite ainsi la transmission du package à d’autres développeurs qui peuvent connaître l’état actuel de la construction du package avant de procéder à d’éventuelles améliorations.
21.4 Question 2 - Exercice de développement du dev_history
Les bases d’un package
Formation expertise
Créer un fichier dev_history.R inscrivant les étapes de développement du package inseexpert, au fur et à mesure des questions de la séquence. Une correction “dev_history” sera fournie après chaque question incluant une étape clé du développement du package (par exemple, la création d’un nouveau script).
Dans un premier temps, mettre à jour le fichier .Rbuildignore via usethis::use_build_ignore. On peut y ajouter les fichiers dev_history.R, LICENCE.md, que le dossier data-raw. Cela permet d’indiquer les fichiers que l’on ne souhaite pas inclure dans la construction du package.
21.5 Correction 2 - dev_history
Les bases d’un package
Formation expertise
On a ajouté au dev_history une modification de la documentation du package avec le choix de la licence MIT :
################################## dev_history.R ################################## 1. =====================================================########################################################## Fichiers à ignorer pour la construction du package ############################################################ Le script dev_history sert à répertorier les actions de constructions du packageusethis::use_build_ignore("dev_history.r")# À exécuter manuellement## Fichier choix de la licenceusethis::use_build_ignore("LICENSE.md")## Si le package embarque des données brutesusethis::use_build_ignore("data-raw")
21.6 Modification de la description du package
Les bases d’un package
Formation expertise
On peut modifier les méta-informations sur le package dans le fichier DESCRIPTION, qui comme son nom l’indique donne une description générale du package. A noter que la description doit impérativement commencer par une majuscule et se terminer par un point.
21.7 Question 3
Les bases d’un package
Formation expertise
Modifier le fichier DESCRIPTION.
On peut par exemple modifier le titre, les auteurs et la description.
21.8 Correction 3
Les bases d’un package
Formation expertise
Package: inseexpert
Title: Toy package from the "R Expertise" formation
Version: 0.0.0.9000
Authors@R:
person("Thomas", "Bayes", , "thomas.bayes@example.com", role = c("aut", "cre"))
Description: This package is developed as part of the "R Expertise" formation from Insee.
License: file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
21.9 Choix de la licence
Les bases d’un package
Formation expertise
La licence permet de définir les droits de propriété intellectuelle associés au package. Ici, on est en train d’écrire un package dans un cadre ouvert et libre d’accès, on peut utiliser la licence MIT, qui est permissive et autorise n’importe qui à réutiliser le contenu.
De même, dans le cadre de travaux menés au sein de l’Insee, la licence MIT est généralement utilisée.
Ouvrir le fichier DESCRIPTION pour constater la mise à jour de la licence.
21.11 Correction 4 - dev_history
Les bases d’un package
Formation expertise
On a ajouté au dev_history une modification de la documentation du package avec le choix de la licence MIT :
################################## dev_history.R ################################## 1. =====================================================########################################################## Fichiers à ignorer pour la construction du package ############################################################ Le script dev_history sert à répertorier les actions de constructions du packageusethis::use_build_ignore("dev_history.r")# À exécuter manuellement## Fichier choix de la licenceusethis::use_build_ignore("LICENSE.md")## Si le package embarque des données brutesusethis::use_build_ignore("data-raw")# 2. =====================================================########################################### DOCUMENTATION DU PACKAGE ################################################ Choix de la licenceusethis::use_mit_license("MIT")
Lorsque l’on souhaite restreindre les usages d’un package, notamment lorsque l’on souhaite en faire l’objet d’un usage commercial, on peut utiliser d’autres licences. Voir ici pour plus d’informations sur les licences.
21.12 Vérification du package
Les bases d’un package
Formation expertise
La fonction devtools::check permet de construire le package à partir des fichiers du dossier et de vérifier qu’il n’y a pas de problème dans la construction du package, comme des éléments manquants ou des tests non réussis. De même, la commande devtools::check() peut être réalisée dans l’onglet “build” de l’interface de RStudio.
21.13 Question 5
Les bases d’un package
Formation expertise
Exécuter la fonction check. Des problèmes sont-ils détectés ?
Une fois le package initialisé, on peut écrire des scripts R dans le dossier R. On peut notamment y écrire des fonctions qui seront exportées par le package. Une fonction peut être créée via la commande usethis::use_r("nom_fonction").
22.2 Question 6
Les bases d’un package
Formation expertise
Créer un script R dans le dossier R nommé calculer_hhi.R et créer dans ce script une fonction nommée calculer_hhi qui permet de calculer l’indice de Herfindahl-Hirschmann associé à un vecteur. Un argument doit permettre de choisir de normaliser l’indice ou non (normalisé par défaut).
On pourra utiliser ce code pour la fonction :
calculer_hhi<-function(data, normalize=TRUE){# On normalise la somme à 1data<-data/sum(data)hhi<-sum(data**2)if(normalize){n<-length(data)hhi<-(hhi-1/n)/(1-1/n)}return(hhi)}
22.3 Correction 6
Les bases d’un package
Formation expertise
usethis::use_r("calculer_hhi")calculer_hhi<-function(data, normalize=TRUE){# On normalise la somme à 1data<-data/sum(data)hhi<-sum(data**2)if(normalize){n<-length(data)hhi<-(hhi-1/n)/(1-1/n)}return(hhi)}
22.4 Correction 6 - dev_history
Les bases d’un package
Formation expertise
On a ajouté au dev_history la création du script R pour la fonction calculer_hhi à l’aide de la fonction usethis::use_r() :
################################## dev_history.R ################################## 1. =====================================================########################################################## Fichiers à ignorer pour la construction du package ############################################################ Le script dev_history sert à répertorier les actions de constructions du packageusethis::use_build_ignore("dev_history.r")# À exécuter manuellement## Fichier choix de la licenceusethis::use_build_ignore("LICENSE.md")## Si le package embarque des données brutesusethis::use_build_ignore("data-raw")# 2. =====================================================########################################### DOCUMENTATION DU PACKAGE ################################################ Choix de la licenceusethis::use_mit_license("MIT")# 3. =====================================================########################################################## Déclaration des scripts des fonctions du package ###########################################################usethis::use_r("calculer_hhi")
Créer un script par fonction et donner un nom identique au script et à la fonction est souvent une bonne solution dans les cas simples. Dans des situations plus complexes, on peut regrouper les fonctions ensemble.
22.5 Test d’une fonction
Les bases d’un package
Formation expertise
Une fois la fonction écrite, on cherche à vérifier qu’elle fonctionne bien.
Pour ce faire, on peut utiliser la commande devtools::load_all() afin de charger le package et ainsi avoir accès à la fonction calculer_hhi dans l’environnement. Dans notre cas, nous aurions pu simplement exécuter le script mais la fonction load_all permet de faire un chargement complet du package et ainsi gérer les dépendances, notamment dans le cas où certaines fonctions du package en appelle d’autres et où il est donc nécessaire de charger l’ensemble du package.
22.6 Test d’une fonction
Les bases d’un package
Formation expertise
La fonction load_all permet d’utiliser les éléments du package sans passer par une installation permanente : Source : https://r-pkgs.org/structure.html
22.7 Test d’une fonction
Les bases d’un package
Formation expertise
La fonction check vue précédemment exécute un build avant d’effectuer les vérifications.
Il est également possible de charger le package via RStudio :
Note
Il est nécessaire d’être dans le .Rproj du package pour que load_all fonctionne. Par ailleurs, il faut bien veiller à partir d’un environnement vierge afin de s’assurer qu’on est en train de tester le pur produit du package et non des choses pré-existantes dans l’environnement. On peut par exemple vérifier que exists("calculer_hhi", where = globalenv(), inherits = FALSE) renvoie FALSE (sinon, redémarrer la session R et effacer l’environnement).
22.8 Question 7
Les bases d’un package
Formation expertise
Charger le package et vérifier le bon fonctionnement de calculer_hhi en l’exécutant sur quelques exemples simples.
NB : Laséquence suivantepermettra d’aller plus loin dans les tests en présentant la notion de test unitaire.
22.10 Documentation et export d’une fonction
Les bases d’un package
Formation expertise
La documentation d’une fonction s’appuie sur la syntaxe de roxygen2 et s’écrit sous forme de commentaires comme suit :
Chaque ligne commence par #'
La documentation se situe immédiatement au dessus de la fonction, sans espace entre les deux
La première ligne est le titre (description courte) de la fonction
On peut ensuite écrire sur plusieurs lignes une description plus longue
Diverses sections peuvent être définies via @ et des mots clés tels que @param pour décrire les paramètres, @return pour décrire le résultat ou @examples pour donner des exemples d’utilisation.
Et @export pour préciser qu’on souhaite exporter la fonction (c’est à dire qu’on souhaite la rendre accessible par l’utilisateur lorsqu’il charge le package)
22.11 Documentation et export d’une fonction
Les bases d’un package
Formation expertise
On a alors une documentation sous cette forme :
#' Description courte en une ligne#'#' Longue description de la fonction qui#' peut être sur plusieurs lignes.#'#' @param x Description de l'argument x#' @param y Description de l'argument y#' @return Description du résultat.#' @examples#' my_function("example", 1)#' my_function("foo", 2)#' @exportmy_function<-function(x, y){paste(x, y)}
Cette structure peut être obtenue via le raccouci clavier CTRL + ALT + Shift + R (en se plaçant dans les paramètres de la fonction) ou via Code > Insert Roxygen Skeleton.
22.12 Documentation et export d’une fonction
Les bases d’un package
Formation expertise
Une fois la documentation complétée, on peut utiliser la commande devtools::document() qui documente et exporte la fonction. Cela a plusieurs effets :
Documentation : la documentation apparaît dans l’onglet “Help” en bas à droite de RStudio
Export : le fichier NAMESPACE se met à jour et fait apparaître les objets exportés (c’est-à-dire contenus dans le namespace)
Note
Le namespace a été évoqué lors de la formation Consolidation - Séquence 2 (manipuler des données simples) - dans la section dédiée aux packages. Il s’agit en fait de l’environnement associé au package. Cet environnement est automatiquement chargé dans l’environnement global avec la fonction library de manière similaire à load avec un fichier .rda. Alternativement, on peut accéder au namespace via la syntaxe nom_package::.
La fonction document est également exécutée automatiquement à chaque fois que la fonction check est lancée.
22.13 Question 8
Les bases d’un package
Formation expertise
Documenter et exporter la fonction calculer_hhi.
22.14 Correction 8
Les bases d’un package
Formation expertise
Dans le fichier calculer_hhi.R :
#' Calcule le HHI#'#' Calcule l'indice de Herfindahl-Hirschmann d'un vecteur.#' Le vecteur est d'abord normalisé pour que sa somme vaille 1.#'#' @param data vecteur numérique pour lequel il faut calculer le HHI#' @param normalize Booléen indiquant s'il faut normaliser le HHI. Par défaut \code{TRUE}#'#' @examples#' calculer_hhi(rep(0.2, 5))#' calculer_hhi(rep(0.2, 5), FALSE)#'#' @exportcalculer_hhi<-function(data, normalize=TRUE){# On normalise la somme à 1data<-data/sum(data)hhi<-sum(data**2)if(normalize){n<-length(data)hhi<-(hhi-1/n)/(1-1/n)}return(hhi)}
Une fois que le namespace a été mis à jour, il est possible d’installer le package via devtools::install(). Le package est alors utilisable comme n’importe quel autre : via library("inseexpert") ou bien on peut utiliser la fonction via inseexpert::calculer_hhi.
Nous avons donc maintenant un nouveau package dans notre librairie !
Pour découvrir plus de façons de partager et installer un package, voir ici.
23 Gestion des dépendances
23.1 Ajouter une dépendance à un package
Les bases d’un package
Formation expertise
Souvent, on a besoin d’utiliser un autre package au sein de son propre package. Il est donc nécessaire d’indiquer que l’on a besoin que d’autres packages soient installés pour que le nôtre puisse fonctionner. Cela vaut également pour des packages qui sont déjà attachés par défaut à l’ouverture d’une session, tels que stats ou utils.
Pour pouvoir indiquer cette dépendance, on utilise la commande usethis::use_package("nom_package")
On note que le fichier DESCRIPTION est mis à jour et les lignes suivantes ont été ajoutées :
Imports:
stats
23.4 Correction 10 - dev_history
Les bases d’un package
Formation expertise
On a rajouté au dev_history une déclaration de dépendance avec le package stats en utilisant la fonction usethis::use_package() :
################################## dev_history.R ################################## 1. =====================================================########################################################## Fichiers à ignorer pour la construction du package ############################################################ Le script dev_history sert à répertorier les actions de constructions du packageusethis::use_build_ignore("dev_history.r")# À exécuter manuellement## Fichier choix de la licenceusethis::use_build_ignore("LICENSE.md")## Si le package embarque des données brutesusethis::use_build_ignore("data-raw")# 2. =====================================================########################################### DOCUMENTATION DU PACKAGE ################################################ Choix de la licenceusethis::use_mit_license("MIT")# 3. =====================================================########################################################## Déclaration des scripts des fonctions du package ###########################################################usethis::use_r("calculer_hhi")# 4. ===================================================################################################## Déclaration des Dépendances de packages #################################################### Mise à jour du fichier DESCRIPTIONusethis::use_package("stats")
23.5 Correction 10 - dev_history
Les bases d’un package
Formation expertise
Par défaut, les packages sont listés dans Imports, mais il existe d’autres types de dépendances, comme Suggests et Depends.
Type de dépendance
Caractéristiques
Imports
Les packages listés sont nécessaires. Ils sont automatiquement installés lorsque l’on installe le package. Ils ne sont cependant pas automatiquement attachés lorsque l’on attache le package. C’est le fonctionnement par défaut.
Suggests
Les packages listés ne sont pas absolument nécessaires mais peuvent être utiles. Ils ne sont pas automatiquement installés. Par exemple, on peut utiliser cette dépendance lorsque l’on utilise un package dans un exemple figurant dans la documentation de l’une des fonctions.
Depends
Les packages listés sont nécessaires. Ils sont automatiquement installés lorsque l’on installe le package. Ils sont automatiquement attachés lorsque l’on attache le package. Par exemple, on peut utiliser cette dépendance lorsque l’on utilise massivement un package au sein du nôtre. Il faut toutefois veiller aux conflits de noms.
Par ailleurs, il est possible de spécifier une version minimale.
23.6 Question 11
Les bases d’un package
Formation expertise
Ajouter une dépendance du type Depends à une version de R supérieure (ou égale) à 4.0
23.7 Correction 11
Les bases d’un package
Formation expertise
usethis::use_package("R", type ="Depends", min_version ="4.0")
23.8 Correction 11 - dev_history
Les bases d’un package
Formation expertise
On a ajouté au dev_history une nouvelle dépendance avec une version minimum de R en utilisant la commande usethis::use_package("R", type = "Depends", min_version = "4.0") :
################################## dev_history.R ################################## 1. =====================================================########################################################## Fichiers à ignorer pour la construction du package ############################################################ Le script dev_history sert à répertorier les actions de constructions du packageusethis::use_build_ignore("dev_history.r")# À exécuter manuellement## Fichier choix de la licenceusethis::use_build_ignore("LICENSE.md")## Si le package embarque des données brutesusethis::use_build_ignore("data-raw")# 2. =====================================================########################################### DOCUMENTATION DU PACKAGE ################################################ Choix de la licenceusethis::use_mit_license("MIT")# 3. =====================================================########################################################## Déclaration des scripts des fonctions du package ###########################################################usethis::use_r("calculer_hhi")# 4. ===================================================################################################## Déclaration des Dépendances de packages #################################################### Mise à jour du fichier DESCRIPTIONusethis::use_package("stats")usethis::use_package("R", type ="Depends", min_version ="4.0")
23.9 Appeler d’autres fonctions
Les bases d’un package
Formation expertise
Il est possible d’appeler d’autres fonction issues des dépendances listées dans DESCRIPTION. Pour ce faire, on peut avoir recours à la syntaxe nom_package::nom_fonction.
23.10 Question 12
Les bases d’un package
Formation expertise
Créer un fichier calculer_variations.R et y définir une fonction calculer_variation qui permet de calculer l’écart-type et le HHI d’un vecteur. Dans un premier temps, on n’utilise pas stats::sd mais seulement sd.
Tester la fonction
Créer une fonction sd avec un argument et renvoyant "toto"
On a ajouté au dev_history la création du script R pour la fonction calculer_variations à l’aide de la fonction usethis::user_r :
################################## dev_history.R ################################## 1. =====================================================########################################################## Fichiers à ignorer pour la construction du package ############################################################ Le script dev_history sert à répertorier les actions de constructions du packageusethis::use_build_ignore("dev_history.r")# À exécuter manuellement## Fichier choix de la licenceusethis::use_build_ignore("LICENSE.md")## Si le package embarque des données brutesusethis::use_build_ignore("data-raw")# 2. =====================================================########################################### DOCUMENTATION DU PACKAGE ################################################ Choix de la licenceusethis::use_mit_license("MIT")# 3. =====================================================########################################################## Déclaration des scripts des fonctions du package ###########################################################usethis::use_r("calculer_hhi")usethis::use_r("calculer_variations")# 4. ===================================================################################################## Déclaration des Dépendances de packages #################################################### Mise à jour du fichier DESCRIPTIONusethis::use_package("stats")usethis::use_package("R", type ="Depends", min_version ="4.0")
On remarque que si on ne précise pas le namespace d’où provient sd, la fonction de notre package peut se retrouver altérée en fonction de l’état de l’environnement.
23.14 Question 13
Les bases d’un package
Formation expertise
Remplacer à nouveau stats::sd par sd dans la fonction calculer_variations.
devtools::document()# Mise à jour de NAMESPACEdevtools::load_all()sd<-function(x)"toto"calculer_variations(c(0.5, 0, 5), FALSE)# sd hhi# 3.0276504 0.1272727
23.16 Correction 13
Les bases d’un package
Formation expertise
Astuce
L’import affecte toutes les fonctions du package. Une pratique courante est de les centraliser dans un fichier comme inseexpert-package.R
On aurait pu attacher l’ensemble du namespace de stats via #' @import stats
De même que pour le développement hors package, on recommande de limiter les imports de packages complets pour notamment éviter des conflits de noms. Il ne faut pas oublier que les packages importés sont suceptibles d’évoluer et donc de nouvelles fonctions pourraient être créées, générant des conflits.
23.17 Exporter des données
Les bases d’un package
Formation expertise
Les packages permettent également d’exporter des données. Il suffit de stocker des fichiers .rda dans le dossier data. Il est recommandé de garder une trace de la création des données, par exemple dans un dossier data-raw.
23.18 Question 14
Les bases d’un package
Formation expertise
On cherche à créer des données nommées inseexpert_data accessibles via le package.
Créer un fichier inseexpert_data.R via la commande usethis::use_data_raw("inseexpert_data").
Définir dans ce fichier un objet inseexpert_data contenant les 20 premières lignes du dataset mtcars, l’exporter via usethis::use_data, et exécuter l’ensemble du script
Charger le package et utiliser ces données avec la fonction calculer_hhi sur l’une des variables
Vérifier s’il y a des problèmes dans le package
23.19 Correction 14
Les bases d’un package
Formation expertise
Exécuter :
usethis::use_data_raw("inseexpert_data")# Note : le fichier .Rbuildignore est mis à jour pour exclure le dossier data-raw
On nous signale que les données n’ont pas été documentées.
23.20 Correction 14 - dev_history
Les bases d’un package
Formation expertise
On a ajouté au dev_history la création des données brutes “inseexpert_data” au sein du package :
################################## dev_history.R ################################## 1. =====================================================########################################################## Fichiers à ignorer pour la construction du package ############################################################ Le script dev_history sert à répertorier les actions de constructions du packageusethis::use_build_ignore("dev_history.r")# À exécuter manuellement## Fichier choix de la licenceusethis::use_build_ignore("LICENSE.md")## Si le package embarque des données brutesusethis::use_build_ignore("data-raw")# 2. =====================================================########################################### DOCUMENTATION DU PACKAGE ################################################ Choix de la licenceusethis::use_mit_license("MIT")# 3. =====================================================########################################################## Déclaration des scripts des fonctions du package ###########################################################usethis::use_r("calculer_hhi")usethis::use_r("calculer_variations")# 4. ===================================================################################################## Déclaration des Dépendances de packages #################################################### Mise à jour du fichier DESCRIPTIONusethis::use_package("stats")usethis::use_package("R", type ="Depends", min_version ="4.0")# 5. =====================================================########################################################## Création de données brutes au sein du package ###########################################################usethis::use_data_raw("inseexpert_data")
23.21 Correction 14 - dev_history
Les bases d’un package
Formation expertise
La documentation des données est importante et se fait avec roxygen2, comme pour les fonctions. On peut créer un fichier R/data.R pour y écrire la documentation. Les différences avec la documentation de fonction vont se trouver dans les tags utilisés : on ne va pas décrire les paramètres ou bien la valeur retournée. En revanche on peut par exemple indiquer la source des données via @source.
La documentation devant être attachée à un objet, on peut utiliser un string avec le nom de la variable :
#' Documentation roxygen2
"inseexpert_data"
23.22 Question 15
Les bases d’un package
Formation expertise
Documenter les données
Inspecter la documentation des données
Vérifier s’il y a des problèmes dans le package
23.23 Correction 15
Les bases d’un package
Formation expertise
Créer un fichier R/data.R :
#' Données de test#'#' Ces données servent pour les exemples du package#'#' @format dataframe#' @source Données originales"inseexpert_data"
Pour un dataframe, il est recommandé de décrire chaque colonne. Par exemple, le package dplyr documente de la façon suivante la table starwars :
#' Starwars characters#'#' The original data, from SWAPI, the Star Wars API, <https://swapi.dev/>, has been revised#' to reflect additional research into gender and sex determinations of characters.#'#' @format A tibble with 87 rows and 14 variables:#' \describe{#' \item{name}{Name of the character}#' \item{height}{Height (cm)}#' \item{mass}{Weight (kg)}#' \item{hair_color,skin_color,eye_color}{Hair, skin, and eye colors}#' \item{birth_year}{Year born (BBY = Before Battle of Yavin)}#' \item{sex}{The biological sex of the character, namely male, female, hermaphroditic, or none (as in the case for Droids).}#' \item{gender}{The gender role or gender identity of the character as determined by their personality or the way they were programmed (as in the case for Droids).}#' \item{homeworld}{Name of homeworld}#' \item{species}{Name of species}#' \item{films}{List of films the character appeared in}#' \item{vehicles}{List of vehicles the character has piloted}#' \item{starships}{List of starships the character has piloted}#' }#' @examples#' starwars"starwars"
23.25 Récapitulatif des étapes
Les bases d’un package
Formation expertise
Pour créer un package, on procède à ces étapes :
Initialisation
File > New Project > New Directory > R package using devtools
Créer un fichier dev_history.R
Modifier la description du package dans le fichier DESCRIPTION
On peut ensuite utiliser le package comme n’importequel autre, par exemple le charger et l’attacher via library
24 Quiz
24.1 Question 1
Les bases d’un package
Formation expertise
Pour effectuer une vérification complète du bon fonctionnement d’un package, y compris les tests, la documentation, et les dépendances, quelle commande doit être utilisée ?
A) devtools::verify_package()
B) devtools::test_package(“mon_package”)
C) devtools::check()
D) devtools::inspect_package(“mon_package”)
24.2 Correction 1
Les bases d’un package
Formation expertise
La réponse correcte est la réponse :
C) devtools::check()
24.3 Question 2
Les bases d’un package
Formation expertise
Lors du développement d’un package avec devtools, quelle commande doit être utilisée pour charger l’ensemble des éléments du package ?
A) devtools::install()
B) devtools::use_package(“package_name”)
C) devtools::load_all()
D) devtools::load_package(“package_name”)
24.4 Correction 2
Les bases d’un package
Formation expertise
La réponse correcte est la réponse :
C) devtools::load_all()
24.5 Question 3
Les bases d’un package
Formation expertise
On définit une fonction fictive en R qui calcule l’offre optimale pour une entreprise cherchant à maximiser ses profits, avec une documentation partielle :
#' Fonction fictive pour calculer l'offre optimale#'#' @param demand_curve Vecteur représentant la courbe de demande#' @param cost_curve Vecteur représentant la courbe de coût#'#' @returns L'offre optimale pour maximiser les profits#'calculate_optimal_offer<-function(demand_curve, cost_curve){# Implémentation d'algorithme pour trouver l'offre optimale}
24.6 Question 3
Les bases d’un package
Formation expertise
Quels compléments doivent être ajoutés à la documentation de la fonction calculate_optimal_offer pour la rendre exhaustive?
A) Ajouter une description détaillée du processus de calcul de l’offre optimale, y compris les formules utilisées.
B) Inclure des exemples pratiques illustrant l’utilisation de la fonction avec des données de demande et de coût spécifiques.
C) Préciser les types de données pris en charge pour les arguments demand_curve et cost_curve et expliquer comment la fonction gère les cas où ces vecteurs sont vides ou de longueurs différentes.
D) Expliquer les conditions dans lesquelles l’algorithme peut ne pas converger et comment gérer ces situations.
E) Toutes les réponses ci-dessus.
24.7 Correction 3
Les bases d’un package
Formation expertise
La réponse correcte est la réponse :
E) Toutes les réponses ci-dessus.
On peut par exemple documenter la fonction de cette façon :
#' Fonction fictive pour calculer l'offre optimale#'#' @param demand_curve (numeric): Vecteur représentant la courbe de demande. Si vide, renvoie NA.#' @param cost_curve (numeric): Vecteur représentant la courbe de coût. Valeur par défaut : 0.#'#' @details L'algorithme recherche un optimum par descente de gradient (cf. https://fr.wikipedia.org/wiki/Algorithme_du_gradient). L'algorithme peut ne pas converger si la demande n'est pas décroissante. Dans ce cas, la fonction renvoie NA et un warning est affiché.#' @examples#' calculate_optimal_offer(c(3, 2, 1), c(1, 2, 3))#' @returns L'offre optimale pour maximiser les profits#'calculate_optimal_offer<-function(demand_curve, cost_curve){# Implémentation d'algorithme pour trouver l'offre optimale}
25 Exercice complémentaire
25.1 Question 1
Les bases d’un package
Formation expertise
Documenter de manière complète la fonction calculer_variations
25.2 Correction 1
Les bases d’un package
Formation expertise
#' Calcule des indicateurs de variations#'#' Calcule l'écart-type ainsi que l'indice de Herfindahl-Hirschmann d'un vecteur.#'#' @param data vecteur numérique pour lequel il faut calculer les indices de variation.#' @param normalize_hhi Booléen indiquant s'il faut normaliser le HHI. Par défaut \code{TRUE}#'#' @examples#' calculer_variations(inseexpert_data)#'#' @importFrom stats sd#' @exportcalculer_variations<-function(data, normalize_hhi=TRUE){result<-c("sd"=sd(data),"hhi"=calculer_hhi(data, normalize_hhi))return(result)}
26 Bibliographie
26.1 Bibliographie
Les bases d’un package
Formation expertise
Pour en savoir plus sur l’utilité et le cycle de vie d’un package, on pourra se référer au livre d’Hadley Wickman et Jennifer Bryan, “R Packages”, disponible gratuitement ici.
16.4 Comment associer une ligne de code à un Breakpoint ?
Améliorer son code
Formation expertise