12  Projets de synthèse et évaluations

12.1 Introduction

Les projets suivants consolident l’ensemble du parcours. Chaque projet comporte : énoncé, objectifs, données, étapes, résultats attendus et solution détaillée. Faites l’exercice avant de lire la correction.

12.2 Projet 1 — Analyse des ventes

12.2.1 Énoncé

Vous êtes analyste pour une petite entreprise de papeterie. On vous confie data/ventes.csv.

12.2.2 Objectifs

  • Nettoyer les données (NA, doublons)
  • Calculer le CA par région et par produit
  • Produire 2 graphiques commentés
  • Rédiger 5–10 lignes de conclusions

12.2.3 Étapes recommandées

  1. Import + diagnostic
  2. distinct(), filtre NA
  3. Agrégats dplyr
  4. Barres CA région + boxplot montants produit
  5. Synthèse écrite

12.2.4 Résultats attendus

  • Table CA par région triée
  • Au moins un outlier ou NA documenté
  • Conclusions actionnables (ex. : région / produit à suivre)

12.2.5 Solution

library(tidyverse)

ventes <- read_csv("data/ventes.csv", show_col_types = FALSE)
cat("Doublons :", sum(duplicated(ventes)), "\n")
#> Doublons : 1
cat("NA region :", sum(is.na(ventes$region)), "\n")
#> NA region : 2
ventes_c <- ventes |>
  distinct() |>
  filter(!is.na(region), !is.na(quantite))

ca_region <- ventes_c |>
  group_by(region) |>
  summarise(ca = sum(montant), n = n(), .groups = "drop") |>
  arrange(desc(ca))
ca_region
#> # A tibble: 4 × 3
#>   region    ca     n
#>   <chr>  <dbl> <int>
#> 1 Ouest  7610.    58
#> 2 Est    7141.    50
#> 3 Sud    5995.    42
#> 4 Nord   5096.    47
ggplot(ca_region, aes(reorder(region, ca), ca)) +
  geom_col(fill = "#1a5276") +
  coord_flip() +
  labs(title = "CA par région", x = NULL, y = "CA") +
  theme_minimal()

12.3 Projet 2 — Données démographiques

12.3.1 Énoncé

Explorez data/demographie.csv : structure de la population, revenus, aberrant âge/revenu.

12.3.2 Objectifs

  • Détecter et traiter les valeurs aberrantes
  • Résumer âge et revenu par ville et sexe
  • Tableau croisé sexe × niveau d’études

12.3.3 Solution

demo <- read_csv("data/demographie.csv", show_col_types = FALSE)

# Aberrants évidents
demo |> filter(age > 100 | revenu_mensuel > 20000)
#> # A tibble: 2 × 6
#>      id   age sexe  ville revenu_mensuel niveau_etudes
#>   <dbl> <dbl> <chr> <chr>          <dbl> <chr>        
#> 1     3   150 Femme Paris           1104 Bac          
#> 2     7    54 Femme Paris          50000 Master
demo_c <- demo |>
  filter(age >= 18, age <= 100, revenu_mensuel < 20000)

demo_c |>
  group_by(ville, sexe) |>
  summarise(
    n = n(),
    age_moy = mean(age),
    revenu_med = median(revenu_mensuel),
    .groups = "drop"
  ) |>
  head(10)
#> # A tibble: 10 × 5
#>    ville     sexe      n age_moy revenu_med
#>    <chr>     <chr> <int>   <dbl>      <dbl>
#>  1 Lille     Femme    14    47.9      2134.
#>  2 Lille     Homme    10    51.5      1751 
#>  3 Lyon      Femme    20    48.2      2386 
#>  4 Lyon      Homme    20    41.1      2152 
#>  5 Marseille Femme    16    52.3      2039 
#>  6 Marseille Homme    18    46.2      2118.
#>  7 Paris     Femme     8    53.4      2038.
#>  8 Paris     Homme    16    41.1      2401 
#>  9 Toulouse  Femme    11    53.4      2289 
#> 10 Toulouse  Homme    15    39.5      2225
demo_c |>
  count(sexe, niveau_etudes) |>
  pivot_wider(names_from = sexe, values_from = n, values_fill = 0)
#> # A tibble: 5 × 3
#>   niveau_etudes Femme Homme
#>   <chr>         <int> <int>
#> 1 Autre            10     9
#> 2 Bac              18    20
#> 3 Doctorat          3     5
#> 4 Licence          26    33
#> 5 Master           12    12

12.4 Projet 3 — Météo

12.4.1 Énoncé

À partir de data/meteo.csv, décrivez la saisonnalité température / précipitations.

12.4.2 Solution

meteo <- read_csv("data/meteo.csv", show_col_types = FALSE) |>
  mutate(date = as.Date(date), mois = floor_date(date, "month"))

mensuel <- meteo |>
  group_by(mois) |>
  summarise(
    temp = mean(temperature_c),
    pluie = sum(precipitations_mm),
    .groups = "drop"
  )

ggplot(mensuel, aes(mois, temp)) +
  geom_line(color = "#148f77", linewidth = 1) +
  labs(title = "Température moyenne mensuelle", x = NULL, y = "°C") +
  theme_minimal()

cor(meteo$temperature_c, meteo$humidite_pct)
#> [1] -0.007141184

12.5 Projet 4 — Régression

12.5.1 Énoncé

Avec data/etudes_notes.csv, modélisez la note selon les heures d’étude et la filière.

12.5.2 Solution

library(broom)
etudes <- read_csv("data/etudes_notes.csv", show_col_types = FALSE)

mod <- lm(note_examen ~ heures_etude + filiere, data = etudes)
tidy(mod)
#> # A tibble: 4 × 5
#>   term            estimate std.error statistic  p.value
#>   <chr>              <dbl>     <dbl>     <dbl>    <dbl>
#> 1 (Intercept)      46.9        1.89    24.8    1.50e-43
#> 2 heures_etude      2.29       0.132   17.3    2.81e-31
#> 3 filiereLettres    0.0554     1.88     0.0294 9.77e- 1
#> 4 filiereSciences  -0.172      1.76    -0.0982 9.22e- 1
glance(mod) |> select(r.squared, adj.r.squared, sigma)
#> # A tibble: 1 × 3
#>   r.squared adj.r.squared sigma
#>       <dbl>         <dbl> <dbl>
#> 1     0.761         0.754  7.45
ggplot(etudes, aes(heures_etude, note_examen, color = filiere)) +
  geom_point(alpha = 0.75) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(title = "Notes vs heures d'étude") +
  theme_minimal()

Rappel : une association positive n’implique pas que « forcer » des heures supplémentaires produira le même effet hors échantillon (causalité, motivation, etc.).

12.6 Projet 5 — Tableau de bord Shiny

12.6.1 Énoncé

Utilisez ou étendez shiny-app/app.R : au moins un jeu de données, un filtre, un résumé et un graphique.

12.6.2 Résultats attendus

  • App qui démarre sans erreur
  • Filtre opérationnel
  • Histogramme réactif

12.6.3 Solution

Voir shiny-app/app.R. Lancement :

shiny::runApp("shiny-app")

12.7 Projet final — Étude complète

12.7.1 Énoncé

Réalisez une étude de A à Z au choix (ventes, démo ou météo) :

  1. Import et contrôle qualité
  2. Préparation documentée
  3. Statistiques descriptives
  4. Au moins 3 graphiques
  5. Une analyse d’association ou régression si pertinent
  6. Rapport Quarto (HTML) de 3–6 pages
  7. Conclusions et limites

12.7.2 Grille d’évaluation (suggestion)

Critère Points
Reproductibilité (chemins, seed, packages) 20
Qualité du nettoyage 20
Pertinence des analyses 20
Graphiques lisibles 15
Interprétation et limites 15
Clarté du rapport 10

12.7.3 Solution type (ventes — squelette)

# 1–2. Préparation
ventes_final <- read_csv("data/ventes.csv", show_col_types = FALSE) |>
  distinct() |>
  filter(!is.na(region), !is.na(quantite), montant > 0) |>
  mutate(date = as.Date(date), mois = floor_date(date, "month"))

# 3. Descriptif
ventes_final |>
  summarise(n = n(), ca = sum(montant), moy = mean(montant))
#> # A tibble: 1 × 3
#>       n     ca   moy
#>   <int>  <dbl> <dbl>
#> 1   197 25842.  131.
# 4. Graphique
ventes_final |>
  count(mois, wt = montant) |>
  ggplot(aes(mois, n)) +
  geom_line() +
  labs(title = "CA mensuel", y = "CA") +
  theme_minimal()

# 5. Association quantité / montant
cor(ventes_final$quantite, ventes_final$montant)
#> [1] 0.6680832

Rédigez ensuite le rapport .qmd en suivant Chapter 10.

12.8 Quiz de révision rapide

  1. Quelle fonction dplyr filtre les lignes ? → filter
  2. Corrélation prouve-t-elle la causalité ? → Non
  3. Commande pour rendre le livre en HTML ? → quarto render --to html
  4. Structure Shiny minimale ? → ui + server + shinyApp
  5. Pourquoi set.seed ? → Reproductibilité du aléatoire

12.9 Points clés

  • Un projet réussi est reproductible, interprété et limité explicitement.
  • Les corrections sont des modèles, pas l’unique réponse acceptable.

12.10 Suite

Chapter 15 : glossaire, aide-mémoires et références.