Ejercicio 16

Enunciado

Cálculo de la duración de un proyecto usando el Método de Montecarlo

Considere el proyecto cuya información se adjunta.

  1. Dibuje el grafo PERT del proyecto.
  1. Determine las ecuaciones de los tiempos tempranos de cada nodo.
  1. Calcule, utilizando las ecuaciones, los tiempos tempranos de cada nodo para 1000 iteraciones del método de MonteCarlo.
  1. Determina la duración media y la desviación típica de la duración del proyecto.
  1. Determine la duración para una probabilidad de completar antes el proyecto del 98%.
import pandas as pd
pd.set_option("display.max_columns", None)
pd.set_option("display.max_rows", None)

import numpy as np
import matplotlib as plt
%matplotlib inline

datos_enunciado = pd.DataFrame([
#  actividad, predecesora, duracion media, desviación típica
     ('A',    '---  ', 10, 1.5 ),
     ('B',    '---  ',  5, 0.4 ),
     ('C',    'A    ',  6, 0.8 ),
     ('D',    'A    ',  2, 0.7 ),
     ('E',    'B,C,D',  7, 1.8 ),
     ('F',    'B,D  ',  8, 0.8 ),
     ('G',    'E,F  ',  4, 1.4 ),
     ('H',    'B    ',  7, 1.6 ),
] ,columns=['activity', 'predecessor', 'mean', 'stdev']).set_index('activity')

datos_enunciado
Tabla 1: Cuadro de datos del enunciado del ejercicio
predecessor mean stdev
activity
A --- 10 1.5
B --- 5 0.4
C A 6 0.8
D A 2 0.7
E B,C,D 7 1.8
F B,D 8 0.8
G E,F 4 1.4
H B 7 1.6

Solución

Apartado 1

  1. Dibuje el grafo PERT del proyecto.
datos_proyecto =  datos_enunciado.copy()
prelaciones = PredecessorTable.from_dataframe_of_strings(datos_proyecto, activity='activity', predecessor='predecessor')
proyecto = prelaciones.create_project()
proyecto.display_pert_construccion(tabla=prelaciones)
paso 0 de 10
Figura 1: Grafo Pert con indicación de los números de nodos

Apartado 2

  1. Determine las ecuaciones de los tiempos tempranos de cada nodo.

\[\begin{aligned} t_1 &= 0\\ t_2 &= t_1 + B\\ t_3 &= t_1 + A\\ t_4 &= \max \left[ t_2 + d_{@∇B⤑ΔF} \; , \; t_3 + D \right] \\ t_5 &= \max \left[ t_3 + C \; , \; t_4 + d_{@∇D⤑ΔE} \right] \\ t_6 &= \max \left[ t_5 + E \; , \; t_4 + F \right] \\ t_7 &= \max \left[ t_6+ G \; , \; t_2 + H \right] \\ \end{aligned} \]

Apartado 3

  1. Calcule, utilizando las ecuaciones, los tiempos tempranos de cada nodo para 1000 iteraciones del método de MonteCarlo.

Generación aleatoria de las duraciones de las actividades

number_of_samples = 1000
activity_names = datos_proyecto.index
np.random.seed(2025)   # reproducibilidad de la simulación
duration = pd.DataFrame([np.random.normal(size = number_of_samples,
                                          loc  = datos_proyecto.loc[task, 'mean',],
                                          scale= datos_proyecto.loc[task, 'stdev'])
                         for task in activity_names
                        ],
                        index=activity_names).T
duration.head()
activity A B C D E F G H
0 9.861415 5.333463 5.664786 2.503223 8.664686 7.610057 3.623105 6.154956
1 11.101428 5.365496 3.876074 2.087051 8.603406 7.468062 2.533273 7.211664
2 7.841677 5.043916 6.088211 2.025739 5.381889 8.508664 4.581449 8.517712
3 9.004867 5.430444 7.022188 3.160544 9.021766 9.098809 1.077909 8.956832
4 9.848908 4.842277 5.885648 0.245137 8.982527 6.907041 4.243551 7.096002

Cálculo de los tiempos tempranos

def row_max(A,B):
    return pd.concat([A,B], axis=1).max(axis=1)
t_early = duration.copy()
t_early.eval("""t_1 = 0
                t_2 = t_1 + B

                t_3 = t_1 + A

                input_D = t_3 + D
                input_f_B_F = t_2 + 0
                t_4 = @row_max(input_D, input_f_B_F)

                input_C = t_3 + C
                input_f_D_E = t_4 + 0
                t_5 = @row_max(input_C, input_f_D_E)

                input_E = t_5 + E
                input_F = t_4 + F
                t_6 = @row_max(input_E, input_F)

                input_G = t_6 + G
                input_H = t_2 + H
                t_7 = @row_max(input_G, input_H)
                """, inplace=True)
tiempos_nodos = ['t_'+ str(num) for num in range(1, 8)]
t_early.loc[0:10, : ]
activity A B C D E F G H t_1 t_2 t_3 input_D input_f_B_F t_4 input_C input_f_D_E t_5 input_E input_F t_6 input_G input_H t_7
0 9.861415 5.333463 5.664786 2.503223 8.664686 7.610057 3.623105 6.154956 0 5.333463 9.861415 12.364638 5.333463 12.364638 15.526201 12.364638 15.526201 24.190886 19.974695 24.190886 27.813991 11.488419 27.813991
1 11.101428 5.365496 3.876074 2.087051 8.603406 7.468062 2.533273 7.211664 0 5.365496 11.101428 13.188479 5.365496 13.188479 14.977502 13.188479 14.977502 23.580908 20.656541 23.580908 26.114181 12.577159 26.114181
2 7.841677 5.043916 6.088211 2.025739 5.381889 8.508664 4.581449 8.517712 0 5.043916 7.841677 9.867416 5.043916 9.867416 13.929888 9.867416 13.929888 19.311777 18.376079 19.311777 23.893226 13.561628 23.893226
3 9.004867 5.430444 7.022188 3.160544 9.021766 9.098809 1.077909 8.956832 0 5.430444 9.004867 12.165411 5.430444 12.165411 16.027055 12.165411 16.027055 25.048821 21.264219 25.048821 26.126730 14.387276 26.126730
4 9.848908 4.842277 5.885648 0.245137 8.982527 6.907041 4.243551 7.096002 0 4.842277 9.848908 10.094045 4.842277 10.094045 15.734556 10.094045 15.734556 24.717083 17.001086 24.717083 28.960635 11.938279 28.960635
5 13.220480 4.487839 5.321716 1.882111 5.743050 8.062424 2.389488 9.403802 0 4.487839 13.220480 15.102590 4.487839 15.102590 18.542196 15.102590 18.542196 24.285246 23.165014 24.285246 26.674733 13.891640 26.674733
6 12.090562 4.622273 7.503299 3.215231 7.030771 9.354858 2.474486 7.696785 0 4.622273 12.090562 15.305793 4.622273 15.305793 19.593862 15.305793 19.593862 26.624632 24.660651 26.624632 29.099118 12.319058 29.099118
7 9.688943 5.897579 7.432042 2.512503 9.238152 8.590238 1.729754 5.757889 0 5.897579 9.688943 12.201446 5.897579 12.201446 17.120985 12.201446 17.120985 26.359137 20.791684 26.359137 28.088891 11.655468 28.088891
8 11.145381 4.808310 5.187720 1.930834 8.373899 8.195887 4.483271 7.611035 0 4.808310 11.145381 13.076215 4.808310 13.076215 16.333101 13.076215 16.333101 24.707000 21.272103 24.707000 29.190272 12.419345 29.190272
9 10.307580 4.555354 4.907546 1.864801 8.928936 8.809729 4.173612 7.718447 0 4.555354 10.307580 12.172381 4.555354 12.172381 15.215127 12.172381 15.215127 24.144063 20.982111 24.144063 28.317675 12.273801 28.317675
10 8.437756 4.992130 6.961868 1.257909 4.746477 8.117629 4.816521 9.720747 0 4.992130 8.437756 9.695664 4.992130 9.695664 15.399623 9.695664 15.399623 20.146100 17.813294 20.146100 24.962621 14.712877 24.962621

Apartado 4

  1. Determina la duración media y la desviación típica de la duración del proyecto.
from pmule import display_histograma_tikz
display_histograma_tikz(t_early['t_7'])
histograma de Montecarlo
t_early['t_7'].describe().round(2)
count    1000.00
mean       27.06
std         2.67
min        18.55
25%        25.20
50%        27.09
75%        28.78
max        35.43
Name: t_7, dtype: float64
f"La duración media del proyecto es:{round(t_early['t_7'].mean(), 1)}, la desviación típica de la duración del proyecto es:{round(t_early['t_7'].std(), 1)}"
'La duración media del proyecto es:27.1, la desviación típica de la duración del proyecto es:2.7'

Apartado 5

  1. Determine la duración para una probabilidad de completar antes el proyecto del 98%.
resultado_1 = round(t_early['t_7'].sort_values(ascending=True).iloc[int(0.98*number_of_samples)],1)
Markdown(f"Podemos ordenar los valores en sentido ascendente y quedarnos con aquél valor superior al 98% de las muestras. De esta manera obtenemos un resultado igual a {resultado_1} periodos")

Podemos ordenar los valores en sentido ascendente y quedarnos con aquél valor superior al 98% de las muestras. De esta manera obtenemos un resultado igual a 32.8 periodos

resultado_2 = round(t_early['t_7'].quantile(q=0.98, interpolation='higher'), 1)
from pmule import display_histograma_tikz
display_histograma_tikz(t_early['t_7'], percentil=0.98)
histograma de Montecarlo
Markdown(f"O bien, utilizando la función `quantile`, obteniendo igualmente un valor de {resultado_2} periodos.")

O bien, utilizando la función quantile, obteniendo igualmente un valor de 32.8 periodos.