(To be completed)

#2. Partie B - Calculs KPI

0.1 B1. Calculez le chiffre d’affaires total (ca) sur l’ensenble de la période . Donnex le montant en Euros (arrondi) et la période couverte.

ca_total <-sum(tx$revenue, na.rm = TRUE)
periode <- range(tx$order_date, na.rm = TRUE)

ca_total
## [1] 311249.8
periode
## [1] "2024-01-01" "2025-06-30"

###interpretation Taille d’activité correcte sur la période analysée. Le CA total s’élève à 311 249.8 sur la période allant de janvier 2024 à juin 2025.

0.2 B2. Calculez la marge contributive totale (CM) sur l’ensemble de la période. Donnez le montant en Euros (arrondi)

CM_total <- sum(tx$contribution_margin, na.rm = TRUE)
round(CM_total, 2)
## [1] 130198.6

0.2.1 interpretation

la marge contributive totale (CM) sur l’ensemble de la période est de 130198.6 Montant disponible pour couvrir la structure et générer du profit.

0.3 B3. Calculez le taux de marge contributive global (CM rate = CM / CA). Interprétez en 1 phrase (sens business).

CM_rate <- CM_total / ca_total
CM_rate_pct <- CM_rate * 100 

CM_rate
## [1] 0.4183089
CM_rate_pct
## [1] 41.83089

0.3.1 interpretation

Pour 100€ vendus, environ 42€ sont disponibles après coûts variables.

0.4 B4. À partir de la table des coûts fixes (annuels), calculez le coût fixe mensuel (annual/12).

fixed$year <- lubridate::year(fixed$month)

annual_2024 <- sum(fixed$fixed_cost[fixed$year == 2024], na.rm = TRUE)

annual_2025_est_h1x2 <- sum(fixed$fixed_cost[fixed$year == 2025], na.rm = TRUE) * 2

annual_est_smooth <- mean(c(annual_2024, annual_2025_est_h1x2))

round(annual_2024, 2)
## [1] 87426.25
round(annual_2025_est_h1x2, 2)
## [1] 87035.82
round(annual_est_smooth, 1)
## [1] 87231

0.4.1 interpretation (To be completed)

Les coûts fixes étant annualisés puis divisés par 12, cela permet de :

Calculer le point mort

Comparer CM mensuelle vs structure

Mesurer le levier opérationnel

Sans cette estimation, impossible d’évaluer la vraie rentabilité.

1 B5. Calculez le profit mensuel : profit_m = CM_m − fixed_cost_month. Donnez : (i) le profit moyen mensuel, (ii) une annualisation simple (×12).

# Calcul de la marge contributive mensuelle (CM_m)
CM_m <- aggregate(contribution_margin ~ month, data = tx, sum)

# Calcul du coût fixe mensuel moyen
fixed_month <- mean(fixed$fixed_cost, na.rm = TRUE)

# Calcul du profit mensuel
CM_m$profit_m <- CM_m$contribution_margin - fixed_month

# Profit moyen mensuel
profit_moyen_mensuel <- mean(CM_m$profit_m, na.rm = TRUE)

# Annualisation simple
profit_annuel_estime <- profit_moyen_mensuel * 12

profit_moyen_mensuel
## [1] -41.42122
profit_annuel_estime
## [1] -497.0547

1.0.1 interepretation

L’intérêt c’est de: Voir si le modèle est structurellement rentable

Identifier volatilité mensuelle

Estimer la capacité de scaling (annualisation ×12)

2 B6. Identifiez le meilleur mois et le moins bon mois en profit (mois + montant).

# CM mensuelle
CM_m_df <- aggregate(contribution_margin ~ month, data = tx, sum, na.rm = TRUE)

# Jointure avec le coût fixe mensuel
CM_m_df <- merge(CM_m_df, fixed, by = "month", all.x = TRUE)

# Profit mensuel)
CM_m_df$profit_m <- CM_m_df$contribution_margin - CM_m_df$fixed_cost

# Profit moyen mensuel + annualisation simple
profit_mean_month <- mean(CM_m_df$profit_m, na.rm = TRUE)
profit_annualized_simple <- profit_mean_month * 12

data.frame(
  profit_mean_month = round(profit_mean_month, 3),
  profit_annualized_simple = round(profit_annualized_simple, 3)
)
##   profit_mean_month profit_annualized_simple
## 1           -41.421                 -497.055
# B6 : meilleur et pire mois
best <- CM_m_df[which.max(CM_m_df$profit_m), c("month","profit_m")]
worst <- CM_m_df[which.min(CM_m_df$profit_m), c("month","profit_m")]

best
##        month profit_m
## 1 2024-01-01 1810.781
worst
##        month  profit_m
## 9 2024-09-01 -1394.534

2.0.1 interpretation

Cela permet de détecter: Saisonnalité Problèmes opérationnels ponctuels Impact d’un canal ou d’un mix spécifique Important pour comprendre si la performance est structurelle ou accidentelle.

#3 Partie C - Segmentation (insights : mix & canaux)

2.1 C1.1 Par product_category, calculez : CA, CM et CM rate. Classez les catégories par CM rate décroissant

C1_1 <- tx %>%
  dplyr::group_by(product_category) %>%
  dplyr::summarise(
    revenue = sum(revenue, na.rm = TRUE),
    cm = sum(contribution_margin, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  dplyr::mutate(
    cm_rate = cm / revenue
  ) %>%
  dplyr::arrange(dplyr::desc(cm_rate))

C1_1
## # A tibble: 5 × 4
##   product_category revenue     cm cm_rate
##   <chr>              <dbl>  <dbl>   <dbl>
## 1 Services          68027. 48061.   0.707
## 2 Accessories       24038. 10316.   0.429
## 3 Office            30375. 10186.   0.335
## 4 Electronics      152081. 49758.   0.327
## 5 Home              36728. 11877.   0.323

2.1.1 interpretation

Chaque euro vendu en Services génère beaucoup plus de marge contributive que les autres catégories. Forte valeur ajoutée, faible coût variable.

2.2 C1.2 Calculez la part de CM de chaque catégorie (CM_cat / CM_total). Identifiez la catégorie qui pèse le plus dans la CM.

cm_total <- sum(tx$contribution_margin, na.rm = TRUE)

C1_2 <- tx %>%
  dplyr::group_by(product_category) %>%
  dplyr::summarise(
    cm_cat = sum(contribution_margin, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  dplyr::mutate(
    cm_total = cm_total,
    cm_share = cm_cat / cm_total
  ) %>%
  dplyr::arrange(dplyr::desc(cm_share))

C1_2
## # A tibble: 5 × 4
##   product_category cm_cat cm_total cm_share
##   <chr>             <dbl>    <dbl>    <dbl>
## 1 Electronics      49758.  130199.   0.382 
## 2 Services         48061.  130199.   0.369 
## 3 Home             11877.  130199.   0.0912
## 4 Accessories      10316.  130199.   0.0792
## 5 Office           10186.  130199.   0.0782

2.2.1 interpretation

Cette catégorie apporte du volume mais consomme beaucoup de coûts variables. Elle “gonfle” le chiffre d’affaires mais dilue la marge globale.

#C1.3 Montrez l’effet “mix produits” : comparez (i) la catégorie qui concentre le plus de CA et (ii) celle au meilleur CM rate. Expliquez en 3–4 lignes pourquoi volume ≠ rentabilité.

# Tableau récapitulatif par catégorie
cat_table <- tx %>%
  dplyr::group_by(product_category) %>%
  dplyr::summarise(
    CA = sum(revenue, na.rm = TRUE),
    CM = sum(contribution_margin, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  dplyr::mutate(CM_rate = CM / CA)

cat_max_CA <- cat_table %>% dplyr::slice_max(CA, n = 1)
cat_best_rate <- cat_table %>% dplyr::slice_max(CM_rate, n = 1)

cat_max_CA
## # A tibble: 1 × 4
##   product_category      CA     CM CM_rate
##   <chr>              <dbl>  <dbl>   <dbl>
## 1 Electronics      152081. 49758.   0.327
cat_best_rate
## # A tibble: 1 × 4
##   product_category     CA     CM CM_rate
##   <chr>             <dbl>  <dbl>   <dbl>
## 1 Services         68027. 48061.   0.707

2.2.2 interpretation

Un produit à faible marge peut représenter 50% du CA mais générer peu de profit. À l’inverse, une catégorie plus petite mais très margée peut être le vrai moteur de rentabilité.

Le pilotage ne doit pas viser “plus de CA”, mais “meilleur mix”.

2.3 C2.1. Par channel, calculez : CA, CM, CM rate et part de CM.

cm_total <- sum(tx$contribution_margin, na.rm = TRUE)

C2_1 <- tx %>%
  dplyr::group_by(channel) %>%
  dplyr::summarise(
    revenue = sum(revenue, na.rm = TRUE),
    cm = sum(contribution_margin, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  dplyr::mutate(
    cm_rate = cm / revenue,
    cm_total = cm_total,
    cm_share = cm / cm_total
  ) %>%
  dplyr::arrange(dplyr::desc(cm_share))

C2_1
## # A tibble: 4 × 6
##   channel     revenue     cm cm_rate cm_total cm_share
##   <chr>         <dbl>  <dbl>   <dbl>    <dbl>    <dbl>
## 1 SEO/Content 112179. 49860.   0.444  130199.    0.383
## 2 Paid Search  90982. 31505.   0.346  130199.    0.242
## 3 Email/CRM    64251. 31478.   0.490  130199.    0.242
## 4 Affiliation  43838. 17355.   0.396  130199.    0.133

2.3.1 interpretation

Email/CRM = meilleur CM rate (~49%)

Canal très rentable : faible coût variable, forte conversion. Excellent levier d’efficacité.

2.4 C2.2. Identifiez : (i) le canal au meilleur CM rate, (ii) le canal qui apporte la plus grande part de CM.

best_rate <- C2_1 %>%
  dplyr::slice_max(cm_rate, n = 1) %>%
  dplyr::select(channel, cm_rate)

best_share <- C2_1 %>%
  dplyr::slice_max(cm_share, n = 1) %>%
  dplyr::select(channel, cm_share)

best_rate
## # A tibble: 1 × 2
##   channel   cm_rate
##   <chr>       <dbl>
## 1 Email/CRM   0.490
best_share
## # A tibble: 1 × 2
##   channel     cm_share
##   <chr>          <dbl>
## 1 SEO/Content    0.383

2.4.1 interpretation

SEO/Content = plus forte contribution en CM (~38%)

Canal scalable : génère beaucoup de volume et donc de marge totale. Moteur principal de croissance.

2.5 C2.3. En 2–3 lignes, expliquez la logique de pilotage : “canal scalable” vs “canal très rentable”.

Un canal scalable permet de croître. Un canal très rentable améliore la marge moyenne. La combinaison des deux optimise à la fois croissance et profitabilité.

2.6 C2.4. En 2–3 lignes, expliquez la logique de pilotage : “canal scalable” vs “canal très rentable”.

library(dplyr)
library(tidyr)
library(lubridate)

# CM par mois et par channel
cm_m_ch <- tx %>%
  group_by(month, channel) %>%
  summarise(cm = sum(contribution_margin, na.rm = TRUE), .groups = "drop") %>%
  arrange(channel, month)

# MoM par channel:
cm_m_ch <- cm_m_ch %>%
  group_by(channel) %>%
  mutate(delta_cm = cm - lag(cm)) %>%
  ungroup()

# Pour chaque mois : 
bridge <- cm_m_ch %>%
  filter(!is.na(delta_cm)) %>%          
  group_by(month) %>%
  summarise(
    top_hausse_segment = channel[which.max(delta_cm)],
    top_hausse_delta_cm = max(delta_cm),
    top_baisse_segment = channel[which.min(delta_cm)],
    top_baisse_delta_cm = min(delta_cm),
    total_delta_cm = sum(delta_cm),
    .groups = "drop"
  )

bridge
## # A tibble: 17 × 6
##    month      top_hausse_segment top_hausse_delta_cm top_baisse_segment
##    <date>     <chr>                            <dbl> <chr>             
##  1 2024-02-01 Affiliation                       30.3 SEO/Content       
##  2 2024-03-01 SEO/Content                     1393.  Affiliation       
##  3 2024-04-01 Email/CRM                       1091.  Paid Search       
##  4 2024-05-01 Paid Search                      871.  SEO/Content       
##  5 2024-06-01 SEO/Content                     1268.  Email/CRM         
##  6 2024-07-01 Email/CRM                        997.  SEO/Content       
##  7 2024-08-01 SEO/Content                      383.  Email/CRM         
##  8 2024-09-01 Paid Search                      311.  Affiliation       
##  9 2024-10-01 Affiliation                      343.  SEO/Content       
## 10 2024-11-01 Email/CRM                       1079.  SEO/Content       
## 11 2024-12-01 SEO/Content                     1469.  Paid Search       
## 12 2025-01-01 Email/CRM                        354.  SEO/Content       
## 13 2025-02-01 SEO/Content                      425.  Email/CRM         
## 14 2025-03-01 Email/CRM                        483.  SEO/Content       
## 15 2025-04-01 Paid Search                      441.  SEO/Content       
## 16 2025-05-01 SEO/Content                      867.  Email/CRM         
## 17 2025-06-01 Email/CRM                        112.  SEO/Content       
## # ℹ 2 more variables: top_baisse_delta_cm <dbl>, total_delta_cm <dbl>

#4 Partie D - Plan d’action (recommandation chiffrée)

2.7 D1 - Proposez 2 actions concrètes pour augmenter la CM (pricing, bundles, upsell, optimisation canal). Pour chaque action : mécanisme attendu (pourquoi ça marche).

1.Révision pricing / remises Augmenter légèrement les prix ou limiter les promotions améliore la marge unitaire. Même si le volume baisse légèrement, la CM totale peut augmenter si l’élasticité est faible.

  1. Bundles & Upsell Ajouter un produit/service à forte marge augmente le panier moyen sans explosion des coûts. Effet multiplicateur sur la CM par commande.

2.8 D2 - Simulation chiffrée : déplacez 5 points de CA d’une catégorie à faible CM rate vers une catégorie à fort CM rate. Calculez l’impact sur la CM (sur la période puis par mois).

months_n <- 18
shift_pct <- 0.05

# CA total période
CA_total <- sum(tx$revenue, na.rm = TRUE)
delta_CA <- shift_pct * CA_total

# CM rate par catégorie
cat_rates <- tx %>%
  dplyr::group_by(product_category) %>%
  dplyr::summarise(
    CA = sum(revenue, na.rm = TRUE),
    CM = sum(contribution_margin, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  dplyr::mutate(CM_rate = CM / CA)

low <- cat_rates %>% dplyr::filter(product_category == "Electronics")
high <- cat_rates %>% dplyr::filter(product_category == "Services")

# Impact CM (période & par mois)
impact_CM_period <- delta_CA * (high$CM_rate - low$CM_rate)
impact_CM_month <- impact_CM_period / months_n

data.frame(
  CA_total = round(CA_total, 2),
  delta_CA_5pct = round(delta_CA, 2),
  low_category = "Electronics",
  low_CM_rate = round(low$CM_rate, 6),
  high_category = "Services",
  high_CM_rate = round(high$CM_rate, 6),
  impact_CM_period = round(impact_CM_period, 2),
  impact_CM_per_month = round(impact_CM_month, 2)
)
##   CA_total delta_CA_5pct low_category low_CM_rate high_category high_CM_rate
## 1 311249.8      15562.49  Electronics    0.327183      Services     0.706501
##   impact_CM_period impact_CM_per_month
## 1          5903.12              327.95

2.8.1 Interpretation

Déplacer 5 points de CA d’Electronics (~32,7%) vers Services (~70,6%) :

Impact : +5 903 € de CM sur la période +328 € par mois Amélioration de rentabilité sans croissance du CA total.

2.9 D3. Priorisez : recommandez un couple (1 canal “scalable” + 1 canal “très rentable”) et justifiez en 2–3 lignes.

Couple recommandé : SEO/Content (volume) Email/CRM (rentabilité)

Objectif : croître sans détériorer le CM rate global.

#5 Partie E - Plan d’action (recommandation chiffrée)

2.10 E1. Robustesse de l’hypothèse “coûts fixes annuels lissés /12”

L’hypothèse consiste à répartir les coûts fixes annuels uniformément sur 12 mois. Cela simplifie l’analyse mais peut fausser la lecture mensuelle.

Limites principales :

Saisonnalité réelle des coûts

Certaines charges ne sont pas linéaires (bonus annuels, primes, maintenance IT, renouvellements logiciels).

Exemple : si une prime annuelle est payée en mars, le lissage masque un pic réel de cash-out.

Contrats non parfaitement annuels

Certains coûts peuvent évoluer en cours d’année (renégociation, embauche, licenciement).

Le modèle suppose une structure constante → ce qui est rarement vrai.

Distorsion du profit mensuel

Un mois peut apparaître rentable alors qu’en réalité il subventionne un futur pic de dépenses.

On mesure une rentabilité “économique moyenne”, pas une rentabilité cash réelle.

Conclusion : Le lissage est acceptable pour une lecture stratégique moyenne, mais insuffisant pour une analyse fine de trésorerie ou de saisonnalité.

2.11 E2. Causalité : attention à l’interprétation des canaux

Observer qu’un canal est performant (ex : SEO ou Email/CRM) ne signifie pas qu’il est la cause directe de la performance.

Pourquoi ?

Corrélation ≠ causalité

Un canal peut apparaître rentable car il capte une demande déjà existante.

Exemple : SEO peut convertir des clients déjà convaincus par d’autres canaux.

Problème d’attribution

Modèle last-click biaisé.

Email peut “récupérer” la conversion finale alors que l’acquisition initiale vient d’un autre canal.

Effet halo entre canaux

Paid Search peut nourrir la notoriété qui améliore ensuite le SEO.

Les canaux interagissent.

Ce qu’il faudrait pour valider la causalité :

A/B tests (couper un canal sur une zone test)

Tests d’incrémentalité

Modèle d’attribution multi-touch

Holdout groups (exclusion partielle d’audience)

2.12 E3. Qualité des données : 2 contrôles essentiels

1- Contrôle des doublons

Vérifier l’unicité des commandes (order_id).

Un doublon gonfle artificiellement le CA et la CM.

Impact direct sur toutes les métriques.

2- Vérification de la granularité des jointures

Si les coûts fixes sont joints à chaque ligne transactionnelle → duplication.

Vérifier les clés de jointure (month, year, category, etc.).

Confirmer qu’on ne multiplie pas artificiellement les coûts.