Mise à l'échelle des prédictions de sous-groupes Monte Carlo
Problème
Lors de l'exécution de simulations Monte Carlo pour la complétion de projets, la prédiction de dates pour les sous-groupes (jalons, priorités, épiques) au sein d'un projet plus large produit des résultats identiques pour tous les groupes, ou les simulations divergent et atteignent le plafond max_weeks.
Contexte / Conditions de déclenchement
- Construction d'un outil de prévision de projets qui prédit les dates pour les jalons individuels ou les groupes de priorités au sein d'un backlog de projet plus large
- Toutes les prédictions de sous-groupes affichent la même date malgré des comptages restants très différents (par exemple, un jalon de 5 éléments affiche la même date qu'un jalon de 46 éléments)
- Les simulations atteignent max_weeks (104) et produisent des dates à plus de 2 ans dans le futur
- Le taux de scope appliqué par groupe crée une vélocité nette négative (les éléments augmentent chaque semaine)
Causes profondes
1. La mise à l'échelle proportionnelle est mathématiquement constante
Si vous mettez à l'échelle le débit proportionnellement :
share = remaining_i / total_remaining
scaled_throughput = overall_throughput * share
weeks = remaining_i / scaled_throughput
= remaining_i / (overall_throughput * remaining_i / total_remaining)
= total_remaining / overall_throughput # CONSTANT pour tous les groupes !
Chaque sous-groupe prédit le même nombre de semaines indépendamment de la taille.
2. Le taux de scope global surpasse le débit du sous-groupe
Si le taux de scope du projet global est de 50 éléments/semaine et que vous l'appliquez à un sous-groupe avec seulement 5 éléments restants (share = 1,6 %), le débit mis à l'échelle pourrait être ~0,6/semaine tandis que le scope mis à l'échelle est ~0,8/semaine. La vélocité nette est négative — la simulation ne converge jamais et atteint max_weeks.
3. created_at GitHub ≠ « Ajouté au tableau »
Le taux de scope calculé à partir des dates created_at reflète le moment où les problèmes GitHub ont été créés, non quand ils ont été ajoutés au tableau du projet. Le triage en masse ou l'importation de vieux problèmes gonfle considérablement le taux de scope apparent.
Solution
Utilisez différents modèles de simulation pour différents types de sous-groupes :
Pour les priorités séquentielles (P0, P1, P2...) : modèle cumulatif
Les priorités plus élevées sont complétées en premier. La prédiction de chaque priorité inclut tous les travaux de priorité supérieure qui doivent être terminés avant :
sorted_priorities = sorted(priorities, key=lambda p: p["name"])
cumulative_before = 0
for p in sorted_priorities:
effective_remaining = cumulative_before + p["remaining"]
result = simulate(
remaining=effective_remaining,
throughput_history=full_project_throughput, # NON mise à l'échelle
scope_rate=0.0, # Ne pas appliquer le scope par groupe
)
result.remaining = p["remaining"] # Afficher le reste réel
cumulative_before += p["remaining"]
Pour les jalons/épiques : modèle de tirage hypergéométrique
Les éléments de chaque jalon sont tirés aléatoirement du pool de travail global. Les jalons plus petits se terminent plus tôt en raison d'une variance plus élevée :
for i in range(n_simulations):
subset_left = remaining
pool_left = total_remaining
weeks = 0
while subset_left > 0 and weeks < max_weeks:
throughput = rng.choice(throughput_samples)
draw_size = min(throughput, pool_left)
if draw_size > 0 and pool_left > 0:
other = pool_left - subset_left
# Combien d'éléments complétés proviennent de ce jalon ?
drawn = rng.hypergeometric(subset_left, max(other, 0), draw_size)
subset_left -= drawn
pool_left -= draw_size
pool_left = max(pool_left, subset_left)
weeks += 1
Principes clés
- Ne pas mettre à l'échelle le débit proportionnellement — cela produit des résultats identiques
- Ne pas appliquer le taux de scope global aux sous-groupes — cela cause une divergence
- Utiliser le débit complet du projet pour les prédictions de priorités (modèle cumulatif)
- Utiliser l'échantillonnage hypergéométrique pour les prédictions de jalons (tirages discrets)
- Afficher le taux de scope à titre informatif plutôt que de l'incorporer dans le MC par groupe
Vérification
- Les sous-groupes avec moins d'éléments restants devraient prédire des dates plus tôt
- Les sous-groupes plus petits devraient avoir des intervalles de confiance plus larges (plus de variance)
- Aucune prédiction ne devrait atteindre le plafond max_weeks dans des conditions normales
- Les prédictions de priorités devraient être ordonnées (P0 < P1 < P2 < P3)
Exemple
Avec un débit de [2, 29, 44, 34, 11, 24, 33, 54, 34, 101, 57, 81, 0] et 303 éléments restants au total :
Avant correction (mise à l'échelle proportionnelle) :
MVP Rel 1 (5 left): Apr 13 # Tous identiques !
MVP Rel 2 (46 left): Apr 13
Release 3 (33 left): Apr 13
Après correction (tirages hypergéométriques) :
MVP Rel 1 (5 left): Apr 6 # Différenciés par taille
MVP Rel 2 (46 left): Apr 13
Release 3 (33 left): Apr 13
Zap Store (10 left): Apr 13
Notes
- Le modèle proportionnel continu (
subset_throughput = throughput * share) est mathématiquement équivalent à « tout se termine quand le projet se termine » car l'équation différentielle d(subset)/dt = -T*(subset/pool) préserve les ratios - La distribution hypergéométrique est le modèle statistique correct pour « tirer sans remplacement dans un pool mixte »
- Pour les très petits sous-groupes (< 5 éléments), le modèle hypergéométrique produit une variance élevée — c'est correct et reflète une incertitude véritable
- Envisagez de plafonner scope_rate à
min(scope_rate, throughput * 0.5)si vous l'utilisez, pour éviter les simulations divergentes