Aller au contenu

Diagrammes Step 06 - Valuation of Volume Effects

Vue d'ensemble du processus

graph TB
    Start([main]) --> M1[main_margin_computation]
    M1 --> M2[main_valuation_computation]
    M2 --> M3[main_cannibalization_computation]

    subgraph "Phase 1: Calcul des marges"
        M1A[Lecture sell_in_base]
        M1B[Calcul marges ajustées]
        M1C[Agrégation par produit/année]
        M1D[Merge avec effects_baseline]

        M1A --> M1B --> M1C --> M1D
    end

    subgraph "Phase 2: Valorisation"
        M2A[Lecture model_with_margin_kpi]
        M2B[Baseline_GM = Volume × Marge]
        M2C[Sauvegarde model_margins]

        M2A --> M2B --> M2C
    end

    subgraph "Phase 3: Cannibalisation"
        M3A[Agrégation famille]
        M3B[Calcul ratio cannibalisation]
        M3C[Répartition volumes/marges]
        M3D[Sauvegarde effects finale]

        M3A --> M3B --> M3C --> M3D
    end

    M1 --> M1A
    M1D --> M2
    M2 --> M2A
    M2C --> M3
    M3 --> M3A
    M3D --> End([Fin])

Flux de données détaillé

flowchart LR
    subgraph "Tables entrée"
        T1[(step_2_03_sell_in_base)]
        T2[(step_4_01_model_with_effects_baseline)]
    end

    subgraph "Tables intermédiaires"
        I1[(step_5_01_model_with_margin_kpi)]
        I2[(step_5_02_model_margins)]
    end

    subgraph "Table sortie"
        O1[(step_5_03_model_cannibalization_effects)]
    end

    T1 --> PC1[Phase 1:<br/>Calcul marges]
    T2 --> PC1
    PC1 --> I1

    I1 --> PC2[Phase 2:<br/>Valorisation]
    PC2 --> I2

    I2 --> PC3[Phase 3:<br/>Cannibalisation]
    PC3 --> O1

    style I1 fill:#e3f2fd
    style I2 fill:#fff3e0
    style O1 fill:#90EE90

Phase 1 : Calcul des marges - Comparaison Galbani/Parmalat

graph TD
    subgraph "Galbani"
        G1[Lecture sell_in_base]
        G2[Extract Year from Period]
        G3[Calcul Adjusted_gross_margin]
        G4[Agrégation EAN×EAN_desc×Year]
        G5[Moyenne pondérée volumes]
        G6[Merge avec baseline effects]

        G1 --> G2 --> G3
        G3 --> G4 --> G5 --> G6

        note1[Adjusted_GM = Gross_margin<br/>+ Supply_chain_gap × Volumes]
        G3 -.-> note1
    end

    subgraph "Parmalat"
        P1[Lecture sell_in_base]
        P2[Vérif marges pré-calculées]
        P3{Marges<br/>existantes?}
        P4[Utiliser Promo_margin_per_unit]
        P5[Fallback: calcul manuel]
        P6[Agrégation EAN×Year<br/>Sans EAN_desc!]
        P7[Merge avec baseline effects]

        P1 --> P2 --> P3
        P3 -->|Oui| P4
        P3 -->|Non| P5
        P4 --> P6
        P5 --> P6
        P6 --> P7

        note2[Marges calculées en Step 3:<br/>Product_margin + Supply_chain_gap<br/>+ Fixed_industrial_costs]
        P2 -.-> note2
    end

    style G3 fill:#e3f2fd
    style P5 fill:#ffebee

Phase 2 : Valorisation baseline

stateDiagram-v2
    [*] --> LoadData: compute_valuation_baseline_effects_{country}

    LoadData --> CalcGM: Chargement step_5_01

    CalcGM --> SaveResults: Calcul simple

    state CalcGM {
        [*] --> Formula
        Formula: Baseline_GM_excl_promo_adjustment =
        Formula: Baseline_Volume × Promo_margin
    }

    SaveResults --> [*]: step_5_02_model_margins

    note right of CalcGM
        Identique pour tous les
        business units
        Simple multiplication
    end note

Phase 3 : Cannibalisation - Flux général

flowchart TD
    Start("compute_cannibalization_{country}") --> Load(Charger step_5_02_model_margins)

    Load --> CalcOriginal(Cannib_GM = Cannib_Volume × Promo_margin)

    CalcOriginal --> Aggregate(Agrégation par famille)

    subgraph "Agrégation famille"
        A1("GROUP BY Category/New_category,<br/>Retailer, Year, Week")
        A2("SUM Uplift_Volume → Family_Uplift")
        A3("SUM Cannib_Volume → Family_Cannib")
        A4("SUM Cannib_GM → Total_Family_GM")

        A1 --> A2
        A1 --> A3
        A1 --> A4
    end

    Aggregate --> A1

    A4 --> PondGM("Ponderated_Family_Cannib_GM =<br/>Total_Family_GM / Family_Cannib_Volume")

    PondGM --> CalcRatio("Ratio_Cannibalizing = Uplift_i / Family_Uplift")

    CalcRatio --> Distribute(Distribution volumes et marges)

    subgraph "Distribution"
        D1("Cannibalizing_Volume =<br/>Ratio × Family_Cannib_Volume")
        D2("Cannibalizing_GM =<br/>Ratio × Family_Cannib × Ponderated_GM")
    end

    Distribute --> D1
    Distribute --> D2

    D2 --> Save(Sauvegarder step_5_03)

Cannibalisation Parmalat - Restriction UHT

graph LR
    subgraph "Filtrage initial"
        F1[Toutes catégories]
        F2{New_category in<br/>UHT milk?}
        F3[UHT normal milk<br/>UHT lactose free milk]
        F4[Autres catégories]

        F1 --> F2
        F2 -->|Oui| F3
        F2 -->|Non| F4
    end

    subgraph "Traitement UHT"
        U1[Calcul cannibalisation normal]
        U2[Agrégation famille]
        U3[Répartition proportionnelle]

        F3 --> U1 --> U2 --> U3
    end

    subgraph "Traitement autres"
        O1[Tous metrics = 0]
        O2[Cannibalizing_Volume = 0]
        O3[Cannibalizing_GM = 0]

        F4 --> O1 --> O2 --> O3
    end

    U3 --> Merge[Concat DataFrames]
    O3 --> Merge

    Merge --> Output[step_5_03 finale]

    style F3 fill:#e8f5e9
    style F4 fill:#ffebee

Formules de calcul - Détail

graph TD
    subgraph "Moyenne pondérée marge (Galbani)"
        MW1("Pour chaque groupe EAN×EAN_desc×Year")
        MW2("weighted_margin_sum = Σ(Adjusted_gross_margin)")
        MW3("total_volumes = Σ(Volumes)")
        MW4("Promo_margin = weighted_margin_sum / total_volumes")

        MW1 --> MW2
        MW1 --> MW3
        MW2 --> MW4
        MW3 --> MW4
    end

    subgraph "Ratio cannibalisation"
        RC1("Galbani: Uplift only")
        RC2("Ratio = Uplift_i / Σ(Uplift_famille)")

        RC3("Default: Uplift + Halo")
        RC4("Ratio = (Uplift_i + Halo_i) /<br/>Σ(Uplift_famille + Halo_famille)")

        RC1 --> RC2
        RC3 --> RC4
    end

    subgraph "Protection division"
        SD1("safe_divide(numerator, denominator)")
        SD2("denominator = 0 → NaN")
        SD3("numerator = ±inf → NaN")
        SD4("result.fillna(default_value)")

        SD1 --> SD2
        SD1 --> SD3
        SD2 --> SD4
        SD3 --> SD4
    end

Gestion des erreurs et cas limites

flowchart TD
    subgraph "Types d'erreurs"
        E1(Division par zéro)
        E2(Colonnes manquantes)
        E3(Volumes nuls)
        E4(Marges extrêmes)
    end

    subgraph "Stratégies de gestion"
        S1("safe_divide() systématique")
        S2(Vérification existence colonnes)
        S3(Protection moyenne pondérée)
        S4(Logs WARNING)
    end

    E1 --> S1
    E2 --> S2
    E3 --> S3
    E4 --> S4

    subgraph "Résultats"
        R1(Continuation pipeline)
        R2(Valeurs NaN neutres)
        R3(Fallback calculations)

        S1 --> R2
        S2 --> R3
        S3 --> R2
        S4 --> R1
    end

Dispatcher principal - apply_*_computation()

flowchart LR
    Start("apply_{operation}_computation")

    Build("Construire nom fonction:<br/>{operation}_{business_unit}")

    Check{Fonction<br/>existe?}

    Start --> Build --> Check

    Check -->|Oui| Specific(Appeler fonction spécifique)
    Check -->|Non| Default("Appeler {operation}_default")

    Specific --> Log1("Log: using BU-specific logic")
    Default --> Log2("Log: using default logic")

    subgraph "Exemples"
        Ex1(compute_margin_italy_galbani)
        Ex2(compute_margin_italy_parmalat)
        Ex3(compute_margin_default)
    end

    style Specific fill:#e8f5e9
    style Default fill:#fff3e0

Points clés de l'implémentation

mindmap
  root((Step 06<br/>Valuation))
    Marges
      Galbani
        Adjusted gross margin
        Supply chain gap
        Moyenne pondérée
      Parmalat
        Marges pré-calculées
        Step 3 réutilisation
        Fallback si absent
    Valorisation
      Simple multiplication
      Baseline × Marge
      Identique tous BU
    Cannibalisation
      Famille = catégorie
      Ratio proportionnel
      Galbani: uplift seul
      Parmalat: UHT only
      Default: uplift + halo
    Techniques
      safe_divide partout
      Agrégations vectorisées
      Gestion mémoire
      Logs détaillés