Démonstrations R - Module 03

Objectif

Construire une analyse de régression sur les campagnes marketing fictives. Les six activités du parcours alimentent un seul document, regression_marketing.qmd. Les productions autonomes des capsules correspondent à ces activités : vous n’avez pas à les refaire deux fois.

Les blocs ci-dessous s’exécutent dans l’ordre, dans le même document. Les résultats présentés sont calculés à partir du CSV du cours. Après ce travail guidé, les exercices vous demandent de transférer la démarche au délai de service et à la satisfaction.

Préparation

  1. Dans RStudio, choisissez File > New Project > New Directory > New Project. Nommez le projet regression-marketing.
  2. Dans Files, créez un dossier data. Placez-y le fichier campagnes_marketing_quebec.csv.
  3. Choisissez File > New File > Quarto Document, puis HTML. Enregistrez regression_marketing.qmd à la racine du projet.
  4. Conservez cet en-tête, puis insérez les blocs R avec Insert > Code Chunk > R.
---
title: "Budget marketing et ventes"
lang: fr
format:
  html:
    embed-resources: true
---
library(tidyverse)

campagnes <- read_csv(
  "data/campagnes_marketing_quebec.csv",
  show_col_types = FALSE
)

Inspecter le tableau

glimpse(campagnes)
Rows: 60
Columns: 10
$ mois             <date> 2025-01-01, 2025-01-01, 2025-01-01, 2025-01-01, 2025…
$ mois_label       <chr> "janvier", "janvier", "janvier", "janvier", "janvier"…
$ region           <chr> "Capitale-Nationale", "Estrie", "Mauricie", "Montréal…
$ canal            <chr> "Infolettre", "Infolettre", "Recherche", "Réseaux soc…
$ saison           <chr> "moyenne", "moyenne", "moyenne", "moyenne", "moyenne"…
$ budget_marketing <dbl> 5814, 3775, 5497, 6215, 5703, 3246, 4927, 2497, 6515,…
$ visites_site     <dbl> 6393, 5235, 6880, 8106, 7107, 4958, 6154, 4117, 7606,…
$ rabais           <dbl> 0.00, 0.15, 0.13, 0.17, 0.17, 0.13, 0.15, 0.08, 0.17,…
$ ventes           <dbl> 121915, 93518, 95109, 121125, 108469, 82306, 95280, 5…
$ satisfaction     <dbl> 7.7, 7.4, 7.5, 7.7, 7.7, 7.1, 7.3, 7.2, 8.5, 7.2, 8.3…

Le tableau contient 60 lignes et 10 colonnes. Une ligne correspond à une région pendant un mois : cinq régions sont observées pendant les douze mois de 2025. Les campagnes sont simulées. Les noms des régions sont réels.

Variable Sens et unité
ventes Montant mensuel des ventes, en dollars canadiens; variable réponse
budget_marketing Budget marketing mensuel, en dollars canadiens; variable explicative
region Région de la campagne
mois Mois de l’observation, représenté par son premier jour
saison Niveau d’activité saisonnière : régulier, moyen ou haut
canal Canal principal de la campagne

Les autres colonnes sont décrites dans la page Données.

campagnes |>
  summarise(
    observations = n(),
    budgets_manquants = sum(is.na(budget_marketing)),
    ventes_manquantes = sum(is.na(ventes)),
    budget_min = min(budget_marketing),
    budget_max = max(budget_marketing)
  )
# A tibble: 1 × 5
  observations budgets_manquants ventes_manquantes budget_min budget_max
         <int>             <int>             <int>      <dbl>      <dbl>
1           60                 0                 0       2497       8857

Les deux variables du modèle sont complètes. Les budgets vont de 2 497 $ à 8 857 $. S’il manquait des valeurs, il faudrait préciser les observations utilisées avant d’ajuster le modèle.

Question de l’activité 3.1 : comment les ventes moyennes varient-elles selon le budget marketing dans ces données? La région et la saison peuvent aussi être liées aux ventes. La question porte sur une association.

Visualiser la relation

ggplot(campagnes, aes(x = budget_marketing, y = ventes)) +
  geom_point(aes(colour = region), alpha = 0.8, size = 2.4) +
  labs(
    title = "Ventes selon le budget marketing",
    x = "Budget marketing mensuel ($)",
    y = "Ventes mensuelles ($)",
    colour = "Région"
  ) +
  theme_minimal(base_size = 12)

Pour l’activité 3.2, décrivez d’abord les points : la tendance globale est croissante et approximativement linéaire, avec une dispersion visible autour de cette tendance. Les couleurs permettent de situer les régions. Ce graphique ne montre pas ce qu’une intervention sur le budget provoquerait.

La corrélation complète la lecture visuelle :

cor(campagnes$budget_marketing, campagnes$ventes)
[1] 0.907859

La corrélation vaut environ 0,908. Elle est sans unité et décrit la relation linéaire. Elle est symétrique : inverser les deux variables ne change pas sa valeur. La régression distingue, elle, la réponse de la variable explicative.

Comprendre la droite

Le modèle s’écrit \(Y_i = \beta_0 + \beta_1 x_i + \varepsilon_i\). Sous l’hypothèse \(\mathrm{E}(\varepsilon_i \mid x_i)=0\), les ventes moyennes au budget \(x_i\) valent \(\beta_0 + \beta_1 x_i\).

Après estimation, la droite est \(\widehat{y}_i = \widehat{\beta}_0 + \widehat{\beta}_1 x_i\). Le résidu \(e_i = y_i - \widehat{y}_i\) se calcule sur les données; il est distinct de l’erreur non observée \(\varepsilon_i\). Les moindres carrés choisissent la droite qui minimise \(\sum_i e_i^2\).

Ajuster le modèle

modele <- lm(ventes ~ budget_marketing, data = campagnes)
coef(modele)
     (Intercept) budget_marketing
       29922.107           13.582 

ventes est à gauche de ~; budget_marketing est à droite. R inclut une ordonnée à l’origine par défaut. Dans la sortie, (Intercept) désigne cette ordonnée et budget_marketing désigne la pente.

Pour voir le résumé complet :

summary(modele)

Call:
lm(formula = ventes ~ budget_marketing, data = campagnes)

Residuals:
     Min       1Q   Median       3Q      Max
-16277.1  -6353.5   -347.8   6892.4  17632.8

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)
(Intercept)      2.992e+04  4.632e+03    6.46 2.35e-08 ***
budget_marketing 1.358e+01  8.236e-01   16.49  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 8339 on 58 degrees of freedom
Multiple R-squared:  0.8242,    Adjusted R-squared:  0.8212
F-statistic: 271.9 on 1 and 58 DF,  p-value: < 2.2e-16

Estimate signifie « estimation » et Std. Error signifie « erreur-type ». Les colonnes de test et les étoiles ne suffisent pas à justifier une décision. Pour ce module, commencez par interpréter les coefficients, puis examinez les résidus et le R².

Interpréter les coefficients

pente_1000 <- coef(modele)[["budget_marketing"]] * 1000
pente_1000
[1] 13582

Pour les activités 3.3 et 3.4, une formulation possible est :

Dans ces données simulées, une différence de 1 000 $ de budget marketing est associée à environ 13 582 $ de ventes moyennes supplémentaires selon la droite.

Ce montant décrit les ventes, pas le profit. Le modèle ne permet pas d’affirmer qu’une augmentation imposée du budget produirait cette hausse.

L’ordonnée estimée vaut environ 29 922 $. Elle correspond aux ventes prédites à budget nul. Or zéro est hors de la plage observée : cette interprétation relève de l’extrapolation. Cela ne justifie pas de supprimer l’ordonnée du modèle.

Incertitude sur la pente

confint(modele, "budget_marketing", level = 0.95)
                    2.5 %   97.5 %
budget_marketing 11.93333 15.23067

L’intervalle de confiance classique à 95 % va d’environ 11,93 à 15,23 $ de ventes par dollar de budget. Pour une différence de 1 000 $, les bornes deviennent environ 11 933 $ et 15 231 $. Il s’agit d’un intervalle sur la pente, pas d’un intervalle pour les ventes d’une nouvelle observation.

NoteCe calcul repose sur des hypothèses

Les intervalles classiques supposent une moyenne linéaire, des erreurs indépendantes et une variance constante. La normalité des erreurs permet les résultats exacts utilisés ici. Sous ces hypothèses, la méthode couvre la pente dans 95 % des répétitions d’échantillonnage.

Les mêmes régions reviennent chaque mois. Il faut donc examiner le contexte régional et temporel avant de faire confiance à ces intervalles. Les calculs illustrent la méthode; ils ne vérifient pas ses hypothèses.

Hypothèse nulle et valeur p

Le test bilatéral de la pente pose \(H_0 : \beta_1 = 0\) contre \(H_1 : \beta_1 \ne 0\). H₀ est l’hypothèse nulle et H₁ l’hypothèse alternative. Le paramètre visé est la pente de population, pas la pente déjà estimée avec les données.

test_pente <- summary(modele)$coefficients["budget_marketing", ]
test_pente
    Estimate   Std. Error      t value     Pr(>|t|)
1.358200e+01 8.236280e-01 1.649046e+01 1.458098e-23 

t value est le rapport entre l’estimation de la pente et son erreur-type, puisque la valeur testée est zéro. Pr(>|t|) est la valeur p bilatérale : sous H₀ et les hypothèses du modèle, la probabilité d’obtenir une statistique au moins aussi éloignée de zéro que celle observée. Une valeur p plus petite indique une moins bonne compatibilité des données avec H₀. Elle ne donne pas la probabilité que H₀ soit vraie.

Au seuil fixé à 5 %, on rejette H₀ si p ≤ 0,05; sinon, on ne la rejette pas. Ne pas rejeter H₀ ne prouve pas que la pente est nulle. Ici, la valeur p est inférieure à 0,001 : le calcul rejette H₀ sous les hypothèses classiques. Il ne mesure ni l’importance pratique de la pente ni un effet causal du budget.

Pour le test t exact, on suppose une moyenne correctement spécifiée et des erreurs de moyenne nulle, indépendantes, normales et de variance constante. Les degrés de liberté valent ici 60 − 2 = 58. La répétition des régions au fil des mois appelle un examen de l’indépendance; le résultat numérique illustre le test sous hypothèses.

Qualité d’ajustement

summary(modele)$r.squared
[1] 0.8242079

Le coefficient de détermination R² vaut environ 0,824. La droite décrit ainsi environ 82,4 % de la variation des ventes dans l’échantillon utilisé pour l’ajuster. Ce pourcentage ne représente ni un taux de prédictions correctes ni une part des ventes causée par le budget. Dans cette régression simple avec ordonnée, R² est égal au carré de la corrélation.

Retrouver R² à partir des écarts

La somme des carrés résiduels (SSE) mesure les écarts à la droite. La somme totale des carrés (SST) mesure les écarts à la moyenne des ventes. Avec une ordonnée à l’origine et une réponse non constante, \(R^2 = 1 - \mathrm{SSE}/\mathrm{SST}\).

sse <- sum(residuals(modele)^2)
sst <- sum((campagnes$ventes - mean(campagnes$ventes))^2)

tibble(
  SSE = sse,
  SST = sst,
  R2_calcule = 1 - sse / sst,
  R2_summary = summary(modele)$r.squared,
  pourcentage = 100 * (1 - sse / sst)
)
# A tibble: 1 × 5
          SSE          SST R2_calcule R2_summary pourcentage
        <dbl>        <dbl>      <dbl>      <dbl>       <dbl>
1 4033405090. 22944176320.      0.824      0.824        82.4

Les deux calculs donnent le même R². Par exemple, si SSE = 30 et SST = 120, alors R² = 1 − 30 / 120 = 0,75, soit 75 %. Ce pourcentage décrit la variation expliquée dans les données d’ajustement.

Résidus et valeurs ajustées

resultats <- campagnes |>
  mutate(
    ventes_predites = fitted(modele),
    residu = residuals(modele)
  )

resultats |>
  select(region, mois_label, budget_marketing, ventes, ventes_predites, residu) |>
  slice_head(n = 6)
# A tibble: 6 × 6
  region             mois_label budget_marketing ventes ventes_predites residu
  <chr>              <chr>                 <dbl>  <dbl>           <dbl>  <dbl>
1 Capitale-Nationale janvier                5814 121915         108888. 13027.
2 Estrie             janvier                3775  93518          81194. 12324.
3 Mauricie           janvier                5497  95109         104582. -9473.
4 Montréal           janvier                6215 121125         114334.  6791.
5 Outaouais          janvier                5703 108469         107380.  1089.
6 Capitale-Nationale février                3246  82306          74009.  8297.

La première observation, en Capitale-Nationale en janvier, a un budget de 5 814 $ et des ventes de 121 915 $. La droite prédit environ 108 888 $, d’où un résidu positif d’environ 13 027 $ : elle sous-estime les ventes de cette observation.

ggplot(resultats, aes(x = ventes_predites, y = residu)) +
  geom_hline(yintercept = 0, colour = "#7A1C24") +
  geom_point(alpha = 0.8, size = 2.4, colour = "#0B4F6C") +
  labs(
    title = "Résidus selon les ventes prédites",
    x = "Ventes prédites ($)",
    y = "Résidu ($)"
  ) +
  theme_minimal(base_size = 12)

Les points ne montrent pas de courbure nette dans ce graphique. La moyenne globale des résidus est nulle par construction pour les moindres carrés avec ordonnée. Ce centrage ne prouve donc pas que le modèle est adéquat. Une courbure, un éventail ou un point isolé appelleraient un examen supplémentaire.

Pour l’activité 3.5, examinez également les régions :

bilan_regions <- resultats |>
  group_by(region) |>
  summarise(
    observations = n(),
    residu_moyen = mean(residu),
    .groups = "drop"
  )

bilan_regions
# A tibble: 5 × 3
  region             observations residu_moyen
  <chr>                     <int>        <dbl>
1 Capitale-Nationale           12        5676.
2 Estrie                       12       -3340.
3 Mauricie                     12        -226.
4 Montréal                     12        2956.
5 Outaouais                    12       -5066.

La droite sous-estime en moyenne les ventes en Capitale-Nationale d’environ 5 676 $ et les surestime en Outaouais d’environ 5 066 $. Ces écarts descriptifs montrent l’intérêt d’examiner les différences régionales. Ils ne constituent pas un test de causalité. Le graphique précédent ne vérifie pas non plus l’indépendance entre les mois d’une même région.

Prédire pour de nouveaux budgets

nouveaux_budgets <- tibble(budget_marketing = c(4000, 6000, 8000))

predictions <- predict(
  modele,
  newdata = nouveaux_budgets,
  interval = "prediction",
  level = 0.95
)

bind_cols(nouveaux_budgets, as_tibble(predictions))
# A tibble: 3 × 4
  budget_marketing     fit     lwr     upr
             <dbl>   <dbl>   <dbl>   <dbl>
1             4000  84250.  67245. 101255.
2             6000 111414.  94560. 128268.
3             8000 138578. 121238. 155919.

Les trois budgets sont dans la plage observée. fit est la valeur prédite; lwr et upr sont les bornes de l’intervalle. Pour 6 000 $ de budget, les ventes prédites sont d’environ 111 414 $, avec un intervalle de prédiction classique à 95 % allant de 94 560 $ à 128 268 $.

La nouvelle observation est un mois dans une région comparable. L’intervalle tient compte de l’incertitude sur la moyenne et de la dispersion d’une nouvelle observation autour de cette moyenne. Sa couverture repose sur les hypothèses du modèle; les diagnostics précédents appellent donc à la prudence.

Pour estimer uniquement la moyenne à un budget donné, on utilise interval = "confidence" :

budget_6000 <- tibble(budget_marketing = 6000)

predict(modele, newdata = budget_6000, interval = "confidence")
       fit      lwr      upr
1 111414.1 109088.5 113739.7
predict(modele, newdata = budget_6000, interval = "prediction")
       fit      lwr    upr
1 111414.1 94560.27 128268

Au même budget et au même niveau de confiance, l’intervalle de prédiction est plus large. Une prédiction hors de 2 497 $ à 8 857 $ serait une extrapolation. Dans cette plage, la comparabilité du contexte reste à vérifier.

Conclusion prudente

Pour l’activité 3.6, une conclusion possible est :

Nous étudions l’association entre le budget marketing et les ventes mensuelles dans 60 observations simulées de campagnes régionales. Une différence de 1 000 $ de budget est associée à environ 13 582 $ de ventes moyennes supplémentaires selon la droite. Le modèle décrit 82,4 % de la variation des ventes, mais les résidus moyens diffèrent selon la région. Cette association ne prouve pas qu’augmenter le budget provoquerait cette hausse des ventes. Avant une recommandation, il faudrait examiner les différences régionales et temporelles et évaluer les prédictions sur de nouvelles observations.

Trace finale

Votre document guidé doit contenir la question, le nuage de points, le code du modèle, les coefficients interprétés, H₀ et la valeur p sous hypothèses, le calcul du R², le diagnostic des résidus et la prédiction pour 6 000 $ avec son intervalle et ses limites. Terminez par votre conclusion.

Dans RStudio, choisissez Session > Restart R, puis Render. Vérifiez que les résultats se recalculent et que les figures sont lisibles dans le HTML. Cette trace est un entraînement; les consignes des travaux évalués sont dans la section Évaluations.

Les lectures du module donnent les références sur l’ajustement, les diagnostics et les intervalles.

Assistant IA Ouvrir le GPT du cours