Avant propos

Dans ce document, les réponses aux exercices sont légèrement différentes de la correction 'standard' car nous allons utiliser les fonctions offertes par le package 'tidyverse'. Ce package regroupe en fait plusieurs packages (dplyr, ggplot2, tibble ...) extremement utiles, ce qui en fait un outil quasiment incontournable aujourd'hui pour la mise en forme et l'analyse de données. Plus généralement, ce document additionel (et les suivants) ont vocation à apporter un certain nombre de conseils et de 'bonnes pratiques' pour coder en R de manière efficace, au delà des simples réponses aux questions. Les codes ci-dessous ne sont qu'un exemple de ce que j'aurais écrit, ce document peut être amené à évoluer, notamment si vous proposez de meilleurs solutions !

Exercice 2 et introduction au tidyverse:

Le codage informatique étant un moyen d'effectuer et d'automatiser rapidement des tâches redondantes, chaque script ayant vocation à être réutiliser devrait comporter une première partie permettant l'importation de tous les principaux outils nécessaires à l'analyse, c'est à dire:

## Chargement des packages (n'oubliez pas de les installer la première fois que vous voulez les utiliser)
library(tidyverse)
library(gridExtra)

## Chargement d'un autre de nos scripts contenant des fonctions utiles
# source('chemin_acces/mes_fonctions_utiles.R')

Notez ici qu'une ligne a été laissée en commentaire. Lorsque vous n'utilisez pas pour le moment une commande qui pourrait être utile plus tard, il est bien plus pratique de la mettre en commentaire temporairement. Il est toujours plus rapide d'enlever le '#' que de retrouver et retaper toute une commande.

Raccourcis clavier utiles:

## Définition du répertoire de travail courant
setwd("C:/Users/user/Google Drive/Travail/Enseignement/ADD STID 2A/Codes R/Donnees")
#setwd("autre_chemin_sur_mon_pc_perso_par_exemple")

## Importation de la base de données
raw_db = read_csv2("Recensement_12.csv")

Ci-dessous notez que l'on utilise la fonction 'read_csv2' qui est l'équivalent du classique 'read.csv2', mais qui importe la base de données au format tibble au lieu du traditionnel dataframe. Ce format, plus pratique notamment pour la visualisation, est au centre de l'écriture en 'version tidyverse'. De plus, les fonctions du tidyverse utilisent traditionellement '_' au lieu de '.' comme séparateur, comme dans 'read_csv2'.

raw_db
## # A tibble: 599 x 12
##       X1   AGE SEXE  REGION STAT_MARI SAL_HOR SYNDICAT CATEGORIE NIV_ETUDES
##    <dbl> <dbl> <chr> <chr>  <chr>       <dbl> <chr>    <chr>     <chr>     
##  1     1    58 F     NE     C            13.2 non      Employe   BAC+3     
##  2     2    40 M     W      M            12.5 <NA>     Construc~ Sans dipl~
##  3     3    29 M     S      C            14   <NA>     Employe   BAC+2     
##  4     4    59 M     NE     D            10.6 <NA>     Transpor~ BAC       
##  5     5    51 M     W      M            13   <NA>     Transpor~ Sans dipl~
##  6     6    19 M     <NA>   C            NA   non      <NA>      <NA>      
##  7     7    64 F     S      M            19.6 <NA>     Producti~ BAC       
##  8     8    23 F     NE     C            13   <NA>     Professi~ BAC+3     
##  9     9    47 M     NW     M            20.1 oui      Construc~ BAC       
## 10    10    66 F     S      D            12.5 non      Employe   BAC       
## # ... with 589 more rows, and 3 more variables: NB_PERS <dbl>, NB_ENF <dbl>,
## #   REV_FOYER <chr>

On voit que le format tibble offre une visualisation des 10 premières lignes de la base de données, et sous le nom de chaque colonne, on peut voir le type de variables qu'elle contient ('chr' : character, 'dbl' : double, ...). On s'aperçoit ainsi facilement que la première colonne est inutile car elle vient probablement d'une sauvegarde non désirée des numéros de ligne. Ainsi, on peut supprimer cette variable avec la commande ci-dessous:

db = raw_db %>% select(- X1)

db
## # A tibble: 599 x 11
##      AGE SEXE  REGION STAT_MARI SAL_HOR SYNDICAT CATEGORIE NIV_ETUDES NB_PERS
##    <dbl> <chr> <chr>  <chr>       <dbl> <chr>    <chr>     <chr>        <dbl>
##  1    58 F     NE     C            13.2 non      Employe   BAC+3            2
##  2    40 M     W      M            12.5 <NA>     Construc~ Sans dipl~       2
##  3    29 M     S      C            14   <NA>     Employe   BAC+2            2
##  4    59 M     NE     D            10.6 <NA>     Transpor~ BAC              4
##  5    51 M     W      M            13   <NA>     Transpor~ Sans dipl~       8
##  6    19 M     <NA>   C            NA   non      <NA>      <NA>            NA
##  7    64 F     S      M            19.6 <NA>     Producti~ BAC              3
##  8    23 F     NE     C            13   <NA>     Professi~ BAC+3            2
##  9    47 M     NW     M            20.1 oui      Construc~ BAC              3
## 10    66 F     S      D            12.5 non      Employe   BAC              1
## # ... with 589 more rows, and 2 more variables: NB_ENF <dbl>, REV_FOYER <chr>

Beaucoup de chose doivent être préciser ici. Tout d'abord, notons que l'on définit une nouvelle variabe 'db' pour ne pas modifier la base de données originale 'raw_db', en travaillant plutôt sur une copie. Il s'agit d'une pratique plus sûre pour éviter de perdre des données en cas de mauvaise manipulation.

De plus nous introduisons un symbole %>% qui parait bizarre au premier abord mais qui est très (très (très)) pratique à utiliser lorsque l'on veut éviter l'accumulation de parenthèses et avoir un code claire. On appelle ce symbole le pipe, car il permet d'écrire des instructions à la suite, comme dans un tuyau (pipe en anglais), plutôt qu'entre parenthèses. Formellement, on a simplement l'équivalence d'écriture: f(x,y) = x %>% f(y) . C'est à dire que le pipe utilise la variable à gauche du symbole comme le premier argument de la function à droite du symbole. Cela peut paraitre assez futile au premier abord mais regardez cet exemple pour vous convaincre de son intérêt:

round(sqrt(exp(sin(5))), digits = 3)
## [1] 0.619
5 %>% sin %>% exp %>% sqrt %>% round(digits = 3)
## [1] 0.619

Ces deux instructions donnent le même résultat, mais on voit que la deuxième est bien plus claire, se lit dans l'ordre 'naturel' d'application des fonctions, et évite des erreurs de parenthèses difficile à debugger. Notez également que lorsque la fonction n'a qu'un argument, les parenthèses sont optionnelles, on peut donc écrire exp ou exp() sans différence.

Enfin, tout l'intérêt du tidyverse vient de l'utilisation d'un nombre réduit de 'verbes' associés à des fonctions très courantes pour la manipulation des données. Voici une liste des verbes les plus courants et de leur effet:

db %>% select(AGE, REGION)
## # A tibble: 599 x 2
##      AGE REGION
##    <dbl> <chr> 
##  1    58 NE    
##  2    40 W     
##  3    29 S     
##  4    59 NE    
##  5    51 W     
##  6    19 <NA>  
##  7    64 S     
##  8    23 NE    
##  9    47 NW    
## 10    66 S     
## # ... with 589 more rows
db %>% filter(AGE < 20)
## # A tibble: 16 x 11
##      AGE SEXE  REGION STAT_MARI SAL_HOR SYNDICAT CATEGORIE NIV_ETUDES NB_PERS
##    <dbl> <chr> <chr>  <chr>       <dbl> <chr>    <chr>     <chr>        <dbl>
##  1    19 M     <NA>   C           NA    non      <NA>      <NA>            NA
##  2    16 M     <NA>   C           NA    <NA>     Gestion ~ <NA>            NA
##  3    19 F     NE     <NA>        NA    <NA>     Transpor~ <NA>            NA
##  4    18 M     S      C           NA    <NA>     Transpor~ BAC              6
##  5    17 F     NE     C            7.9  <NA>     Transpor~ Sans dipl~       5
##  6    19 M     NW     C           11    <NA>     Employe   BAC              5
##  7    18 F     NE     C           NA    non      Professi~ <NA>             6
##  8    18 M     NE     C            8    non      Professi~ BAC              4
##  9    18 F     S      C            7.25 <NA>     Gestion ~ BAC              4
## 10    17 F     W      C            9    <NA>     Transpor~ Sans dipl~       3
## 11    19 F     S      C            3.05 <NA>     Transpor~ BAC              4
## 12    19 F     NE     C            8    <NA>     Transpor~ Sans dipl~       3
## 13    19 F     <NA>   <NA>        NA    <NA>     Gestion ~ <NA>             4
## 14    19 M     S      C           NA    <NA>     Transpor~ BAC              6
## 15    19 M     NW     M            9    <NA>     Producti~ BAC              4
## 16    16 M     NE     C            8    <NA>     Producti~ Sans dipl~       4
## # ... with 2 more variables: NB_ENF <dbl>, REV_FOYER <chr>
db %>% mutate(X1 = 1:599, .before = AGE)
## # A tibble: 599 x 12
##       X1   AGE SEXE  REGION STAT_MARI SAL_HOR SYNDICAT CATEGORIE NIV_ETUDES
##    <int> <dbl> <chr> <chr>  <chr>       <dbl> <chr>    <chr>     <chr>     
##  1     1    58 F     NE     C            13.2 non      Employe   BAC+3     
##  2     2    40 M     W      M            12.5 <NA>     Construc~ Sans dipl~
##  3     3    29 M     S      C            14   <NA>     Employe   BAC+2     
##  4     4    59 M     NE     D            10.6 <NA>     Transpor~ BAC       
##  5     5    51 M     W      M            13   <NA>     Transpor~ Sans dipl~
##  6     6    19 M     <NA>   C            NA   non      <NA>      <NA>      
##  7     7    64 F     S      M            19.6 <NA>     Producti~ BAC       
##  8     8    23 F     NE     C            13   <NA>     Professi~ BAC+3     
##  9     9    47 M     NW     M            20.1 oui      Construc~ BAC       
## 10    10    66 F     S      D            12.5 non      Employe   BAC       
## # ... with 589 more rows, and 3 more variables: NB_PERS <dbl>, NB_ENF <dbl>,
## #   REV_FOYER <chr>
db %>% summarise(Mean_age = mean(AGE))
## # A tibble: 1 x 1
##   Mean_age
##      <dbl>
## 1     41.8
db %>% arrange(AGE)
## # A tibble: 599 x 11
##      AGE SEXE  REGION STAT_MARI SAL_HOR SYNDICAT CATEGORIE NIV_ETUDES NB_PERS
##    <dbl> <chr> <chr>  <chr>       <dbl> <chr>    <chr>     <chr>        <dbl>
##  1    16 M     <NA>   C           NA    <NA>     Gestion ~ <NA>            NA
##  2    16 M     NE     C            8    <NA>     Producti~ Sans dipl~       4
##  3    17 F     NE     C            7.9  <NA>     Transpor~ Sans dipl~       5
##  4    17 F     W      C            9    <NA>     Transpor~ Sans dipl~       3
##  5    18 M     S      C           NA    <NA>     Transpor~ BAC              6
##  6    18 F     NE     C           NA    non      Professi~ <NA>             6
##  7    18 M     NE     C            8    non      Professi~ BAC              4
##  8    18 F     S      C            7.25 <NA>     Gestion ~ BAC              4
##  9    19 M     <NA>   C           NA    non      <NA>      <NA>            NA
## 10    19 F     NE     <NA>        NA    <NA>     Transpor~ <NA>            NA
## # ... with 589 more rows, and 2 more variables: NB_ENF <dbl>, REV_FOYER <chr>

Finallement, tout l'intérêt vient de la combinaison d'une suite d'instructions à l'aide des différents 'verbes', pour effectuer des tâches complexes. Par exemple, cette commande retourne la moyenne et l'écart type des salaires horaires des personnes de moins de 20 ans, en excluant les valeurs NA:

db %>% filter(AGE < 20) %>% 
       filter( !is.na(SAL_HOR) ) %>% 
       summarise(Moyenne = mean(SAL_HOR), Ecart_type = sd(SAL_HOR))
## # A tibble: 1 x 2
##   Moyenne Ecart_type
##     <dbl>      <dbl>
## 1    7.91       2.12

Maintenant que nous avons introduit ces nouveaux outils, utilisons les dans le cadre de l'exercice 2.

  1. Même si cela n'apporte ici aucune plus value particulière, notons que l'on peut utiliser la fonction 'summary' avec le pipe:
db %>% summary
##       AGE            SEXE              REGION           STAT_MARI        
##  Min.   :16.00   Length:599         Length:599         Length:599        
##  1st Qu.:29.00   Class :character   Class :character   Class :character  
##  Median :42.00   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :41.85                                                           
##  3rd Qu.:53.50                                                           
##  Max.   :80.00                                                           
##                                                                          
##     SAL_HOR       SYNDICAT          CATEGORIE          NIV_ETUDES       
##  Min.   : 2.0   Length:599         Length:599         Length:599        
##  1st Qu.:10.5   Class :character   Class :character   Class :character  
##  Median :14.5   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :17.7                                                           
##  3rd Qu.:21.0                                                           
##  Max.   :99.0                                                           
##  NA's   :160                                                            
##     NB_PERS           NB_ENF        REV_FOYER        
##  Min.   : 1.000   Min.   :0.0000   Length:599        
##  1st Qu.: 2.000   1st Qu.:0.0000   Class :character  
##  Median : 3.000   Median :0.0000   Mode  :character  
##  Mean   : 3.119   Mean   :0.5443                     
##  3rd Qu.: 4.000   3rd Qu.:1.0000                     
##  Max.   :13.000   Max.   :6.0000                     
##  NA's   :46       NA's   :46
  1. Pour calculer le pourcentage de valeurs manquantes, il existe de nombreuses façon de procéder, parmi lesquelles:
db %>% is.na %>% colMeans %>% mean %>% '*'(100)
## [1] 14.11443

Successivement, nous vérifions si les valeurs du tableau sont manquantes ou non, puis nous calculons la proportion moyenne dans chaque colonne, puis la moyenne des valeurs des colonnes, et enfin nous multiplions le résultat par 100 pour obtenir un pourcentage. N'hésitez pas à executer les commandes morceaux par morceaux pour bien voir l'effet successif de chacune.

  1. Il estmaintenant facile de garder le pourcentage de valeurs manquantes par colonnes puis de rajouter une commande pour sélectionner celles qui sont supérieur à 70%. Ensuite, il suffit d'exclure ces colonnes à l'aide de la fonction select_if, qui selectionne les colonnes qui vérifient une condition:
var_suppr = db %>% is.na %>% colMeans %>% '*'(100) %>% '>'(70)

db_tidy = db %>% select_if( !var_suppr )
  1. On veut effectuer un même filtrage sur les lignes maintenant. En pratique, le tidyverse sert aussi à éviter d'utiliser un trop grand nombre de noms de variables intermédiaires inutiles (raw_db, db, db_tidy, ...), en donnant directement une longue suite d'instructions pour nettoyer la base. C'est pourquoi en général nous n'utiliseront que le nom raw_db pour la base de données brute, telle qu'importée, et db, qui est un nom court et pratique, pour la base de données nettoyée sur laquelle les analyses sont effectuées. Ainsi, en appliquant tout d'un coup dans cet exemple:
row_suppr = db %>% is.na %>% rowMeans %>% '*'(100) %>% '>'(60)

db = raw_db %>% select( - X1 ) %>%
                select_if( !var_suppr) %>% 
                filter( !row_suppr )
db
## # A tibble: 570 x 10
##      AGE SEXE  REGION STAT_MARI SAL_HOR CATEGORIE NIV_ETUDES NB_PERS NB_ENF
##    <dbl> <chr> <chr>  <chr>       <dbl> <chr>     <chr>        <dbl>  <dbl>
##  1    58 F     NE     C           13.2  Employe   BAC+3            2      0
##  2    40 M     W      M           12.5  Construc~ Sans dipl~       2      0
##  3    29 M     S      C           14    Employe   BAC+2            2      0
##  4    59 M     NE     D           10.6  Transpor~ BAC              4      1
##  5    51 M     W      M           13    Transpor~ Sans dipl~       8      1
##  6    64 F     S      M           19.6  Producti~ BAC              3      0
##  7    23 F     NE     C           13    Professi~ BAC+3            2      0
##  8    47 M     NW     M           20.1  Construc~ BAC              3      0
##  9    66 F     S      D           12.5  Employe   BAC              1      0
## 10    26 M     NE     M            9.96 Gestion ~ BAC+2            3      0
## # ... with 560 more rows, and 1 more variable: REV_FOYER <chr>
  1. Même s'il est bien sûr possible de spécifier à la main le nom des variables qualitatives et quantitatives, il est toujours préférable d'effectuer cette tâche automatiquement, surtout si on a un grand nombre de variables:
quali = db %>% select_if(is.character)
quali
## # A tibble: 570 x 6
##    SEXE  REGION STAT_MARI CATEGORIE                   NIV_ETUDES   REV_FOYER 
##    <chr> <chr>  <chr>     <chr>                       <chr>        <chr>     
##  1 F     NE     C         Employe                     BAC+3        40 - < 60 
##  2 M     W      M         Construction et Maintenance Sans diplome < 40      
##  3 M     S      C         Employe                     BAC+2        >= 100    
##  4 M     NE     D         Transports et Service       BAC          < 40      
##  5 M     W      M         Transports et Service       Sans diplome >= 100    
##  6 F     S      M         Production et Agriculture   BAC          60 - < 100
##  7 F     NE     C         Profession liberale         BAC+3        40 - < 60 
##  8 M     NW     M         Construction et Maintenance BAC          40 - < 60 
##  9 F     S      D         Employe                     BAC          < 40      
## 10 M     NE     M         Gestion et Vente            BAC+2        < 40      
## # ... with 560 more rows
quanti = db %>% select_if(is.double)
quanti
## # A tibble: 570 x 4
##      AGE SAL_HOR NB_PERS NB_ENF
##    <dbl>   <dbl>   <dbl>  <dbl>
##  1    58   13.2        2      0
##  2    40   12.5        2      0
##  3    29   14          2      0
##  4    59   10.6        4      1
##  5    51   13          8      1
##  6    64   19.6        3      0
##  7    23   13          2      0
##  8    47   20.1        3      0
##  9    66   12.5        1      0
## 10    26    9.96       3      0
## # ... with 560 more rows
  1. Pour l'imputation des valeurs manquantes se fait par la moyenne pour les variables continues et par la médianne pour les variables discrètes:
quanti_imput = quanti %>% mutate(AGE = if_else(is.na(AGE), mean(AGE, na.rm=TRUE), AGE),
                                 SAL_HOR = if_else(is.na(SAL_HOR), mean(SAL_HOR, na.rm=TRUE), SAL_HOR),
                                 NB_PERS = if_else(is.na(NB_PERS), median(NB_PERS, na.rm=TRUE), NB_PERS),
                                 NB_ENF = if_else(is.na(NB_ENF), median(NB_ENF, na.rm=TRUE), NB_ENF))

quanti_imput %>% is.na %>% sum
## [1] 0

Et on vérifie qu'il n'y a en effet plus de valeurs manquantes.

Exercice 3

  1. De manière générale, il est préférable d'éviter les diagrammes en camembert, qui sont peu informatifs visuellement et peuvent facilement être trompeurs. Nous allons donc favoriser les diagrammes en barre pour représenter les fréquences de nos variables qualitatives. Dans toute la suite, nous allons utiliser le package ggplot2 (inclu dans le tidyverse) qui fournit une grammaire très pratique et personnalisable pour la conception de graphiques de qualité en R. La fonction indispensable pour créer un graphique est ggplot(), qui peut prendre en argument la base de données à utiliser. Ensuite, chaque élement à ajouter au graphique est séparé par un signe '+'. Ici nous utilisons geom_bar() pour créer un diagramme en barres. Pour tout graphique, il est nécessaire de spécifier un ensemble d'aesthetics dans la fonction aes(), pour indiquer quelles variables seront utilisées sur les axes des abscisses et des ordonnées notamment. Des paramètres supplémentaires peuvent être ajoutés, utilisez l'aide pour plus de détails.
 gg1 = ggplot(quali) + geom_bar(aes(x = SEXE, y = ..prop.., group = 1)) 
 gg2 = ggplot(quali) + geom_bar(aes(x = REGION, y = ..prop.., group = 1))
 gg3 = ggplot(quali) + geom_bar(aes(x = STAT_MARI, y = ..prop.., group = 1))
 gg4 = ggplot(quali) + geom_bar(aes(x = CATEGORIE, y = ..prop.., group = 1), position="dodge") + coord_flip()
 gg5 = ggplot(quali) + geom_bar(aes(x = NIV_ETUDES, y = ..prop.., group = 1), position="dodge") + coord_flip()
 gg6 = ggplot(quali) + geom_bar(aes(x = REV_FOYER, y = ..prop.., group = 1))
 
 grid.arrange(gg1, gg2, gg3, gg6, gg4, gg5, ncol = 2, nrow = 3)

La fonction grid.arrange(), issue du package gridExtra, permet d'afficher simplement plusieurs plots dans un même cadre structuré.

    1. Il est possible de visualiser et discuter les principaux indicateurs sur la distributions des variables quantitatives après imputation à l'aide de la fonction 'summary':
quanti_imput %>% summary
##       AGE           SAL_HOR         NB_PERS           NB_ENF      
##  Min.   :16.00   Min.   : 2.00   Min.   : 1.000   Min.   :0.0000  
##  1st Qu.:29.00   1st Qu.:12.00   1st Qu.: 2.000   1st Qu.:0.0000  
##  Median :42.00   Median :17.73   Median : 3.000   Median :0.0000  
##  Mean   :41.66   Mean   :17.73   Mean   : 3.116   Mean   :0.5281  
##  3rd Qu.:53.00   3rd Qu.:18.50   3rd Qu.: 4.000   3rd Qu.:1.0000  
##  Max.   :80.00   Max.   :99.00   Max.   :13.000   Max.   :6.0000
  1. Cette question vise à montrer que la variance est codée avec sa définition non biaisée par défaut dans R. La function pull du tidyverse permet d'extraire la colonne du tableau qui nous intéresse et d'en faire un vecteur. On remarque que la fonction 'var' donne un résultat légérement différent du codage strict selon la définition de la variance:
quanti_imput %>% pull(AGE) %>% var
## [1] 196.9684
quanti_imput %>% pull(AGE) %>% scale(center = T, scale = F) %>% '^'(2) %>% mean
## [1] 196.6228
  1. Pour les variables quantitatives continues, on peut utiliser une boite à moustache pour afficher visuellement les principales caractériques de position et dispersion:
gg7 = ggplot(quanti_imput) + geom_boxplot(aes(y = AGE))
gg8 = ggplot(quanti_imput) + geom_boxplot(aes(y = SAL_HOR))

grid.arrange(gg7, gg8, ncol = 2)

Comme souvent, là où la distribution des âges et relativement homogène, celle des salaires présente de nombreuses valeurs extremes, appelés aussi outliers. On peut égallement présenter la distribution empirique complète à l'aide d'un histogramme:

gg9 = ggplot(quanti_imput) + geom_histogram(aes(x = AGE))
gg10 = ggplot(quanti_imput) + geom_histogram(aes(x = SAL_HOR))
grid.arrange(gg9, gg10, ncol = 2)

  1. Pour des raisons esthétiques ou pour d'autres arguments plus poussés, il est parfois intéressant de procéder à un lissage de ces distributions pour en faire de vrais densités de probabilité. La fonction geom_density() utilise le lissage à noyaux pour nous aider dans cette tâche. De plus, pour faire la démontration du potentiel de personnalisation de ggplot2, nous ajoutons quelques options pour améliorer la qualité visuelle.
gg11 = ggplot(quanti_imput) + geom_density(aes(x = AGE)) + theme_classic() + xlab('Age') +
                              ylab('Densité de probabilité')
gg12 = ggplot(quanti_imput) + geom_density(aes(x = SAL_HOR)) + theme_classic() + xlab('Salire horaire') +
                              ylab('Densité de probabilité')
grid.arrange(gg11, gg12, ncol = 2)

Exercice 4

  1. Pour le bien d'un analyse descriptive bivariée, il est possible d'afficher les boxplots reliants deux variables. Ceci se fait toujours en ggplot2 en utilisant la function geom_boxplot(), mais nous précisons maintenant dans les aesthetics quelle variable sera en abscisse et laquelle sera en ordonnée. Pour mieux illustrer les différentes modalités, nous utilisons également l'argument fill lorsque l'axe des absisses est trop chargé:
db_imput = quanti_imput %>% bind_cols(quali)

gg13 = ggplot(db_imput) + geom_boxplot(aes(x = SEXE , y = AGE)) + ggtitle('Age selon Sexe')
gg14 = ggplot(db_imput) + geom_boxplot(aes(x = NIV_ETUDES , y = AGE, fill = NIV_ETUDES)) + ggtitle('Age selon Etudes')
gg15 = ggplot(db_imput) + geom_boxplot(aes(x = CATEGORIE , y = AGE, fill = CATEGORIE)) + ggtitle('Age selon Catégorie')
gg16 = ggplot(db_imput) + geom_boxplot(aes(x = REV_FOYER , y = AGE)) + ggtitle('Age selon Revenus')

grid.arrange(gg13, gg14, gg15, gg16, ncol = 2, nrow = 2)

Pour aller plus loin

Pour ceux qui veulent utiliser d'autres effets visuels pour affichées des informations supplémentaires, ggplot2 propose de nombreuses modifications du concept de boxplot à cet effet. Par exemple, si l'on veut étudier simultanement 3 variables, il est possible d'utiliser les 2 axes ainsi que les couleurs comme élements dedistinctions:

ggplot(db_imput) + geom_boxplot(aes(x = NIV_ETUDES , y = SAL_HOR, fill = SEXE)) 

Ce graph nous permet d'analyser en un coup d'oeil l'effet du niveau d'étude sur le salaire horaire, ainsi que les inégalités hommes/femmes (malheureusement toujours évidentes sur ce graph).

D'un point de vu plus esthétique, il est également possible d'utiliser la commande geom_violin(), pour afficher un violin plot qui a l'avantage de représenter la distribution des données plus finement tout en restant simple visuellement:

ggplot(db_imput) + geom_violin(aes(x = NIV_ETUDES  , y = SAL_HOR, fill = NIV_ETUDES)) 

Pour finir, lorsque l'on étudie des variables quantitatives continues, il est généralement utile de visualiser directement la totalité du nuage de point avec geom_points():

ggplot(db_imput) + geom_point(aes(x = AGE  , y = SAL_HOR)) 

On voit qu'étonnament l'âge semble influer peu sur le salaire horaire, mais encore une fois, il est possible de faire une distinction par couleur selon une troisième variable qui a son importance: le niveau d'étude.

ggplot(db_imput) + geom_point(aes(x = AGE  , y = SAL_HOR, color = NIV_ETUDES)) 

En faisant cette distinction, il est plus clair que le salaire des dipômés d'un bac+2 ou moins évolue en fait très peu avec l'âge, alors que pour les bac+3, +5 et +8 les augmentations de salaire sont plus fréquentes au cours du temps.