George Pashev

Website of George Pashev (Jidai Mirai)

Scientist, Programmer, Data Scientist, Enterpreneur

Монте Карло симулация за оценка на проектен бюджет

Монте Карло симулация за оценка на проектен бюджет

1. Въведение и значимост

Монте Карло симулацията е мощен инструмент за оценка на риска и несигурността в проектното управление. При управлението на софтуерни проекти, точното определяне на бюджета е критично за успеха на проекта.

Защо е важна тази задача?

  • Помага за по-точна оценка на необходимия бюджет
  • Позволява количествена оценка на рисковете
  • Дава възможност за определяне на реалистични буфери
  • Подпомага вземането на информирани решения

2. Методология

Монте Карло симулацията за бюджетно планиране се базира на принципа на многократното случайно семплиране. Вместо да разчитаме на единични точкови оценки, които често се оказват неточни, методът генерира хиляди възможни сценарии, вземайки предвид вероятностните разпределения на различните компоненти на бюджета. Това ни позволява да получим не просто една прогнозна стойност, а цяло разпределение на възможните резултати, което много по-добре отразява реалната несигурност в проектното планиране.

Особено важен аспект на методологията е интегрирането на рисковите фактори. За разлика от традиционното бюджетно планиране, където рисковете често се отчитат чрез фиксиран процент буфер, Монте Карло симулацията позволява моделиране на сложни взаимодействия между различните рискове. Всеки рисков фактор се характеризира с вероятност на възникване и потенциално въздействие, като в симулацията тези рискове могат да се материализират независимо един от друг, създавайки множество различни комбинации от сценарии. Това води до много по-реалистична оценка на необходимия буфер, базирана на действителната рискова експозиция на проекта.

2.1. Основни компоненти

  • Идентификация на ключови променливи разходи
  • Определяне на разпределения на вероятностите
  • Интегриране на рискови фактори
  • Многократно симулиране на сценарии
  • Статистически анализ на резултатите

2.2. PERT разпределение

Използваме PERT (Program Evaluation and Review Technique) разпределение със следните оценки:

  • Оптимистична (O): Базова сума
  • Най-вероятна (M): Базова сума + 50% от буфера
  • Песимистична (P): Максимална сума с отчитане на рискове

Formula: Expected Value = (O + 4M + P) / 6

3. Псевдокод на решението

ФУНКЦИЯ monte_carlo_simulation(iterations, activities, risks):
    резултати = празен_масив()
    
    ЗА ВСЯКО i ОТ 1 ДО iterations:
        общ_бюджет = 0
        
        ЗА ВСЯКА дейност В activities:
            // Генериране на случайна стойност по PERT разпределение
            стойност = pert_random(
                дейност.оптимистична,
                дейност.най_вероятна,
                дейност.песимистична
            )
            
            // Прилагане на рискови фактори
            ЗА ВСЕКИ риск В risks:
                АКО random() < риск.вероятност:
                    стойност *= (1 + риск.въздействие)
                    
            общ_бюджет += стойност
        
        // Добавяне на допълнителни разходи
        общ_бюджет *= 1.3  // 30% за технологии и обучения
        
        добави(резултати, общ_бюджет)
    
    ВЪРНИ резултати

ФУНКЦИЯ анализирай_резултати(резултати, планиран_бюджет):
    средна_стойност = изчисли_средно(резултати)
    стандартно_отклонение = изчисли_std(резултати)
    персентил_90 = изчисли_персентил(резултати, 90)
    вероятност_превишаване = изчисли_вероятност_превишаване(резултати, планиран_бюджет)
    
    ВЪРНИ {
        средна_стойност,
        стандартно_отклонение,
        персентил_90,
        вероятност_превишаване
    }
        

Обяснение на псевдокода

Основна функция monte_carlo_simulation

Функцията приема три параметра:

  • iterations - брой повторения на симулацията (обикновено 10000)
  • activities - списък с дейностите и техните оценки
  • risks - списък с рисковите фактори

За всяка итерация функцията:

  1. Инициализира нов общ бюджет за текущата итерация
  2. Преминава през всяка дейност и генерира случайна стойност според PERT разпределението
  3. За всяка генерирана стойност прилага рисковите фактори според техните вероятности
  4. Добавя допълнителните разходи (30% за технологии и обучения)
  5. Запазва крайния резултат за тази итерация

PERT разпределение

Функцията pert_random реализира PERT разпределението чрез:

  • Използване на Beta разпределение за апроксимация
  • Изчисляване на средна стойност по формулата (O + 4M + P) / 6
  • Трансформиране на генерираните стойности в желания интервал

Функция за анализ

Функцията анализирай_резултати извършва статистически анализ чрез:

  • Изчисляване на средната стойност на всички симулации
  • Определяне на стандартното отклонение за оценка на волатилността
  • Изчисляване на 90-ти персентил за определяне на препоръчителния буфер
  • Определяне на вероятността за превишаване на планирания бюджет

Тези метрики дават цялостна картина на риска и необходимия буфер.

Ключови аспекти на имплементацията

  • Използване на вероятностно разпределение вместо фиксирани стойности
  • Независимо прилагане на рискови фактори за по-реалистично моделиране
  • Отчитане на допълнителни разходи като процент от основния бюджет
  • Статистически анализ за извличане на значими заключения

4. Python имплементация

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats

# Define project activities and their estimates
activities = {
    'Project Manager': {
        'optimistic': 6460.48,
        'most_likely': 6945.02,
        'pessimistic': 7429.55 * 1.2
    },
    'Senior Dev 1': {
        'optimistic': 26103.69,
        'most_likely': 28061.47,
        'pessimistic': 30019.24 * 1.3
    },
    'Senior Dev 2': {
        'optimistic': 24886.95,
        'most_likely': 26753.47,
        'pessimistic': 28619.99 * 1.3
    },
    'Junior Dev 1': {
        'optimistic': 6797.73,
        'most_likely': 7307.56,
        'pessimistic': 7817.39 * 1.15
    },
    'Junior Dev 2': {
        'optimistic': 6244.19,
        'most_likely': 6712.51,
        'pessimistic': 7180.82 * 1.15
    },
    'QA Engineer': {
        'optimistic': 5532.38,
        'most_likely': 5947.31,
        'pessimistic': 6362.24 * 1.25
    }
}

# Risk factors from risk register
risk_factors = {
    'integration_issues': {'probability': 0.8, 'impact': 0.25},
    'performance_issues': {'probability': 0.8, 'impact': 0.20},
    'requirement_changes': {'probability': 0.8, 'impact': 0.15},
    'technical_challenges': {'probability': 0.6, 'impact': 0.20}
}

def pert_random(opt, likely, pess, size=1):
    """Generate random values using PERT distribution"""
    alpha = 4
    mean = (opt + alpha * likely + pess) / (alpha + 2)
    variance = ((pess - opt) ** 2) / 36
    a = ((mean - opt) * (2 * pess - opt - mean)) / variance
    b = (a * (pess - mean)) / (mean - opt)
    return np.random.beta(a, b, size=size) * (pess - opt) + opt

def run_simulation(n_iterations=10000):
    """Run Monte Carlo simulation"""
    results = []
    
    for _ in range(n_iterations):
        iteration_total = 0
        
        for activity, estimates in activities.items():
            cost = pert_random(
                estimates['optimistic'],
                estimates['most_likely'],
                estimates['pessimistic']
            )[0]
            
            for risk in risk_factors.values():
                if np.random.random() < risk['probability']:
                    cost *= (1 + risk['impact'])
            
            iteration_total += cost
        
        iteration_total *= 1.3
        results.append(iteration_total)
    
    return np.array(results)

def analyze_results(simulation_results):
    """Analyze simulation results"""
    planned_budget = 126772.39
    
    mean_cost = np.mean(simulation_results)
    std_dev = np.std(simulation_results)
    percentile_90 = np.percentile(simulation_results, 90)
    overrun_prob = np.mean(simulation_results > planned_budget)
    recommended_buffer = percentile_90 - planned_budget
    
    print(f"\nSimulation Analysis Results:")
    print(f"Mean Expected Cost: {mean_cost:,.2f} лв.")
    print(f"Standard Deviation: {std_dev:,.2f} лв.")
    print(f"90th Percentile Cost: {percentile_90:,.2f} лв.")
    print(f"Probability of Budget Overrun: {overrun_prob:.1%}")
    print(f"Recommended Additional Buffer: {max(0, recommended_buffer):,.2f} лв.")
    
    plt.figure(figsize=(10, 6))
    plt.hist(simulation_results, bins=50, density=True, alpha=0.7)
    plt.axvline(planned_budget, color='r', linestyle='dashed', label='Planned Budget')
    plt.axvline(mean_cost, color='g', linestyle='dashed', label='Mean Simulated Cost')
    plt.axvline(percentile_90, color='y', linestyle='dashed', label='90th Percentile')
    plt.title('Monte Carlo Simulation Results')
    plt.xlabel('Total Project Cost (лв.)')
    plt.ylabel('Probability Density')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

# Run simulation and analyze results
results = run_simulation(10000)
analyze_results(results)
        

5. Заключение

Тази симулация предоставя ценна информация за:

  • Очакваната средна стойност на проектния бюджет
  • Вероятността за превишаване на планирания бюджет
  • Препоръчителния размер на буфера
  • Разпределението на възможните крайни стойности

Важно е да се отбележи, че симулацията е толкова добра, колкото са входните данни. Редовното актуализиране на оценките и рисковите фактори е ключово за поддържане на точността на модела.

fulltext

Keywords

resultssimulationбюджетmeanстойнострезултатиpertcostrandomlikelypercentileразпределениефакториriskprobabilityoptimisticpessimisticactivitiesbudgetprint