Comparer les coûts des camps de jour
Quels tarifs peut-on additionner pour quatre semaines avec garde, et quels cas restent non comparables?
À produire : Un tableau des unités, un tableau des sous-totaux recalculés, un graphique et une justification des exclusions.
Prérequis : Savoir importer un CSV et exécuter un script R. Comprendre une jointure et la propagation des valeurs manquantes.
Préparation enseignante
Extraire entièrement le ZIP, ouvrir Donnees-bleues.Rproj dans RStudio, puis exécuter installer-packages.R avec Internet avant la séance. Le script datasets/camps-de-jour-quebec/activite-comparer-couts.R utilise ensuite les huit tables fournies, sans téléchargement. Les consignes portent sur la version figée du 5 octobre 2026.
Télécharger la trousse avec les données
33 Ko. Préparation : 05/10/2026 à 14:27 (heure du Québec).
Les fichiers de données sont inclus dans la trousse.
Conditions de la source · Provenance et empreinte du ZIP
Fichiers inclus
-
programmes.csv: 10 lignes, 7 colonnes. -
faits.csv: 103 lignes, 7 colonnes. -
tarifs.csv: 108 lignes, 19 colonnes. -
scenario.csv: 10 lignes, 9 colonnes. -
calculs_scenario.csv: 16 lignes, 20 colonnes. -
qualite.csv: 8 lignes, 4 colonnes. -
preuves.csv: 166 lignes, 15 colonnes. -
sources.csv: 14 lignes, 13 colonnes.
Contexte
Le pilote des camps de jour rapproche des tarifs publiés dans dix municipalités. Les tables de la version du 5 octobre 2026 permettent de suivre chaque composante du scénario jusqu’à sa source; elles n’observent pas les dépenses réelles des familles.
Consignes
- Exécuter le script. Expliquer pourquoi ses 108 lignes de tarifs ne représentent pas 108 camps.
- À l’aide des champs
periodeetbase_facturation, repérer les lignes qui ne sont pas des prix hebdomadaires par enfant. - Refaire le scénario de quatre semaines pour un premier enfant résident de sept ans, avec une couverture de 7 h 30 à 17 h 30. Vérifier les identifiants de tarifs, les multiplicateurs et les frais de dossier.
- Interpréter le point et l’intervalle d’Acti-Famille. Indiquer quelles hypothèses rendent ce calcul conditionnel.
- Expliquer les trois cas non calculables sans remplacer les montants manquants par zéro. Comparer les deux grains de facturation affichés pour Victoriaville.
- Rédiger une conclusion de 150 à 200 mots sur ce que ces sous-totaux permettent de comparer. Nommer les frais inconnus, les unités et le périmètre territorial.
Limites à faire nommer
Le scénario exclut les aides, crédits fiscaux, sorties facultatives et pénalités. Il additionne des montants affichés, dont le traitement fiscal n’est souvent pas précisé. Il ne recherche pas le forfait d’achat le moins cher. Une place disponible, une prise en charge effective ou un montant réellement payé n’est pas observé.
Vérifier le travail
- Chaque somme comporte une période et une base de facturation explicites.
- Le tableau conserve six sommes de postes documentés, un calcul conditionnel et trois cas non calculables.
- Les trois cas exclus sont justifiés par une lacune précise des sources.
- La conclusion évite une estimation provinciale et une interprétation de dépenses observées.
Objectifs et adaptations
Objectifs
- Relier un tarif à sa source avec une clé vérifiée.
- Distinguer rang d'enfant, taille de famille et période de facturation.
- Identifier les informations nécessaires pour un calcul comparable.
Adaptations
- Débuter avec les sorties du script et interpréter seulement les catégories de prix.
- Approfondir en évaluant l'effet du choix semaine ou saison, sans présumer les règles d'inscription non documentées.
Statut documenté : Script exécuté dans la trousse; utilisation en classe non documentée.
Contribution pédagogique : Aurélien Nicosia. Usage en cours non documenté.
- Ajout
- Mise à jour
Script complet
Afficher le script R
# Comparer des composantes documentées dans le pilote 2026.
# Exécuter depuis la racine de la trousse entièrement extraite.
library(readr)
library(dplyr)
library(tidyr)
library(ggplot2)
programmes <- read_csv("data/processed/camps-de-jour-quebec/programmes.csv", na = c("", "NA"), show_col_types = FALSE)
tarifs <- read_csv("data/processed/camps-de-jour-quebec/tarifs.csv", na = c("", "NA"), show_col_types = FALSE)
faits <- read_csv("data/processed/camps-de-jour-quebec/faits.csv", na = c("", "NA"), show_col_types = FALSE)
preuves <- read_csv("data/processed/camps-de-jour-quebec/preuves.csv", na = c("", "NA"), show_col_types = FALSE)
sources <- read_csv("data/processed/camps-de-jour-quebec/sources.csv", na = c("", "NA"), show_col_types = FALSE)
scenario <- read_csv("data/processed/camps-de-jour-quebec/scenario.csv", na = c("", "NA"), show_col_types = FALSE)
composantes <- read_csv("data/processed/camps-de-jour-quebec/calculs_scenario.csv", na = c("", "NA"), show_col_types = FALSE)
qualite <- read_csv("data/processed/camps-de-jour-quebec/qualite.csv", na = c("", "NA"), show_col_types = FALSE)
# Vérifier les relations avant les jointures; une ligne de tarif n'est pas un camp.
stopifnot(!anyDuplicated(programmes$programme_id), !anyDuplicated(tarifs$tarif_id),
!anyDuplicated(preuves$preuve_id), !anyDuplicated(sources$source_id),
all(tarifs$programme_id %in% programmes$programme_id),
all(tarifs$preuve_id %in% preuves$preuve_id),
all(preuves$source_id %in% sources$source_id))
print(tarifs |> count(periode, base_facturation, name = "lignes_de_tarif"))
print(faits |> count(statut, name = "champs"))
# Recalculer à partir des identifiants de tarifs et des multiplicateurs publiés,
# plutôt qu'employer les montants déjà copiés dans calculs_scenario.csv.
recalcul <- composantes |> select(programme_id, tarif_id, multiplicateur) |>
left_join(select(tarifs, tarif_id, montant_min, montant_max), by = "tarif_id") |>
group_by(programme_id) |> summarise(
montant_min_recalcule = sum(montant_min * multiplicateur),
montant_max_recalcule = sum(montant_max * multiplicateur), .groups = "drop") |>
left_join(scenario, by = "programme_id")
stopifnot(!anyNA(recalcul$montant_min_recalcule),
all(abs(recalcul$montant_min_recalcule - recalcul$montant_min) < 1e-8),
all(abs(recalcul$montant_max_recalcule - recalcul$montant_max) < 1e-8))
print(recalcul |> select(municipalite, montant_min_recalcule, montant_max_recalcule, statut))
print(scenario |> filter(is.na(montant_min)) |> select(municipalite, reserve))
# Les deux tarifs de Victoriaville ci-dessous ont des grains différents :
# deuxième enfant à la semaine, et chaque enfant d'une famille de deux à la journée.
print(tarifs |> filter(programme_id == "victoriaville_municipal",
(periode == "semaine" & rang_min == 2) |
(periode == "jour" & famille_min == 2)) |>
select(composante, montant_min, periode, base_facturation, rang_min, famille_min, condition))
documentation_tarifs <- tarifs |> left_join(
select(preuves, preuve_id, source_id, url, retrieved_at, ligne_txt, localisation), by = "preuve_id")
print(documentation_tarifs |> filter(programme_id == "rimouski_municipal", residence == "resident",
rang_min == 1, periode == "semaine") |> select(composante, montant_min, url, retrieved_at))
print(qualite)
graphique <- recalcul |>
mutate(programme = if_else(programme_id == "sherbrooke_actifamille", "Sherbrooke (Acti-Famille)", municipalite)) |>
ggplot(aes(x = reorder(programme, montant_min_recalcule),
y = montant_min_recalcule, colour = statut)) +
geom_linerange(aes(ymin = montant_min_recalcule, ymax = montant_max_recalcule), linewidth = 1.4) +
geom_point(size = 3) + coord_flip() +
scale_colour_manual(values = c(somme_tarifs_documentes = "#1e5a81", calcul_conditionnel = "#bf853c"),
labels = c(calcul_conditionnel = "Calcul conditionnel", somme_tarifs_documentes = "Postes documentés")) +
labs(x = NULL, y = "Sous-total affiché (CAD)", colour = NULL,
title = "Quatre semaines avec couverture de 7 h 30 à 17 h 30",
subtitle = "Premier enfant résident de 7 ans; pilote été 2026",
caption = "Sorties facultatives et aides exclues; taxes souvent non précisées.\nCe calcul ne recherche pas le forfait d'achat le moins cher.") +
theme_minimal(base_size = 12) + theme(legend.position = "bottom")
print(graphique)