#Introducción
El problema plantea una situación de decisión empresarial bajo incertidumbre en la que una compañía debe definir si conviene contratar una consultora antes de elegir el tamaño de planta a implementar, considerando que esta información es imperfecta pero puede influir en la decisión final. La complejidad surge porque la empresa no solo enfrenta la incertidumbre del mercado, sino también la necesidad de actualizar sus creencias mediante un enfoque bayesiano tras observar el dictamen de la consultora, lo que convierte el análisis en un proceso secuencial de dos etapas de decisión. En este contexto, la problemática radica en determinar si el costo de adquirir información adicional realmente mejora la calidad de la decisión y maximiza el valor monetario esperado, o si es más conveniente decidir directamente con la información inicial, evaluando cuidadosamente las alternativas de planta bajo distintos escenarios y niveles de riesgo.
# ====================================================
# ÁRBOL BAYESIANO COMPLETO — TechParts S.A.
# Bayes integrado en árbol de decisión de 2 etapas
# ====================================================
library(ggplot2); library(tidyr); library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
Se cargan las librerías necesarias para el desarrollo del modelo y el análisis de resultados:
library(ggplot2)
Permite realizar gráficos y visualizaciones de datos, útiles para
interpretar resultados y análisis de sensibilidad.
library(dplyr)
Facilita la manipulación y transformación de datos, como filtrado,
selección y creación de variables.
library(tidyr)
Se utiliza para organizar y estructurar los datos en formatos adecuados
para el análisis, especialmente al trabajar con tablas y
modelos.
# ---- Datos ----
pagos <- matrix(c(
-200000, 100000, 500000,
-50000, 200000, 300000,
100000, 150000, 180000
), nrow=3, byrow=TRUE)
rownames(pagos) <- c("Grande","Mediana","Pequeña")
prior <- c(0.20, 0.45, 0.35)
likel_F <- c(0.10, 0.40, 0.90)
likel_D <- 1 - likel_F
Se definen los pagos y probabilidades necesarias para el árbol bayesiano:
pagos <- matrix(c(...), nrow=3, byrow=TRUE)
Crea una matriz de beneficios o pérdidas según el
tamaño del proyecto (grande, mediana, pequeña) y el escenario
económico.
rownames(pagos) <- c("Grande","Mediana","Pequeña")
Asigna nombres a las filas de la matriz para identificar los
proyectos.
prior <- c(0.20, 0.45, 0.35)
Define las probabilidades a priori de ocurrencia de
cada tipo de proyecto antes de obtener información adicional.
likel_F <- c(0.10, 0.40, 0.90)
Probabilidades de obtener información favorable para
cada tipo de proyecto.
likel_D <- 1 - likel_F
Probabilidades de obtener información desfavorable,
complementando likel_F.
# ---- Bayes ----
actualizar <- function(prior, likel) {
conj <- prior*likel
list(post=conj/sum(conj), P_E=sum(conj))
}
bF <- actualizar(prior, likel_F)
bD <- actualizar(prior, likel_D)
Se define la función de actualización bayesiana y se calculan las probabilidades posteriores:
actualizar <- function(prior, likel)
Crea una función para aplicar el Teorema de Bayes,
combinando probabilidades iniciales y verosimilitudes.
conj <- prior*likel
Calcula las probabilidades conjuntas multiplicando
prior por likelihood.
list(post=conj/sum(conj), P_E=sum(conj))
Devuelve:
post: las probabilidades posteriores
normalizadas (suman 1).P_E: la probabilidad de
evidencia.bF <- actualizar(prior, likel_F)
Calcula las probabilidades posteriores cuando la información es
favorable.
bD <- actualizar(prior, likel_D)
Calcula las probabilidades posteriores cuando la información es
desfavorable.
# ---- VME por escenario ----
vme_all <- function(p) {
v <- pagos %*% p
list(vme=as.vector(v), mejor=rownames(pagos)[which.max(v)],
max_vme=max(v))
}
Se define la función para calcular el Valor Monetario Esperado (VME) de cada proyecto según un vector de probabilidades:
vme_all <- function(p)
Crea una función que recibe un vector de probabilidades p
para calcular el VME.
v <- pagos %*% p
Calcula el VME de cada proyecto mediante producto
matricial entre pagos y probabilidades.
list(vme=as.vector(v), mejor=rownames(pagos)[which.max(v)], max_vme=max(v))
Devuelve una lista con:
vme: VME de cada proyecto.mejor: nombre del proyecto con mayor
VME.max_vme: valor máximo de VME.r_prior <- vme_all(prior)
r_F <- vme_all(bF$post)
r_D <- vme_all(bD$post)
vme_con_info <- bF$P_E*r_F$max_vme + bD$P_E*r_D$max_vme
veii <- vme_con_info - r_prior$max_vme
Se calculan los VME con y sin información, y el valor de la información:
r_prior <- vme_all(prior)
Calcula el VME usando las probabilidades a priori,
antes de obtener información.
r_F <- vme_all(bF$post)
Calcula el VME si la información es favorable, usando
probabilidades posteriores favorables.
r_D <- vme_all(bD$post)
Calcula el VME si la información es desfavorable,
usando probabilidades posteriores desfavorables.
vme_con_info <- bF$P_E*r_F$max_vme + bD$P_E*r_D$max_vme
Calcula el VME esperado considerando la información,
ponderando por la probabilidad de obtener información favorable o
desfavorable.
veii <- vme_con_info - r_prior$max_vme
Calcula el Valor Esperado de la Información Perfecta
(VEII), es decir, cuánto se gana en promedio al disponer de la
información antes de decidir.
cat("===== ÁRBOL BAYESIANO — TECHPARTS =====\n")
## ===== ÁRBOL BAYESIANO — TECHPARTS =====
cat(sprintf("Sin consultora → %s: $%s\n",
r_prior$mejor, format(round(r_prior$max_vme), big.mark=",")))
## Sin consultora → Mediana: $185,000
cat(sprintf("Si Favorable → %s: $%s\n",
r_F$mejor, format(round(r_F$max_vme), big.mark=",")))
## Si Favorable → Grande: $333,010
cat(sprintf("Si Desfavor. → %s: $%s\n",
r_D$mejor, format(round(r_D$max_vme), big.mark=",")))
## Si Desfavor. → Pequeña: $133,608
cat(sprintf("VME con info imperfecta: $%s\n",
format(round(vme_con_info), big.mark=",")))
## VME con info imperfecta: $236,300
cat(sprintf("VEII = $%s (máx a pagar por la consultora)\n",
format(round(veii), big.mark=",")))
## VEII = $51,300 (máx a pagar por la consultora)
Se imprimen los resultados de los VME y el valor de la información de forma clara:
cat("===== ÁRBOL BAYESIANO — TECHPARTS =====\n")
Muestra un encabezado del análisis.
cat(sprintf("Sin consultora → %s: $%s\n", r_prior$mejor, ...))
Imprime el proyecto óptimo sin información adicional y
su VME correspondiente.
cat(sprintf("Si Favorable → %s: $%s\n", r_F$mejor, ...))
Imprime el proyecto óptimo si la información es
favorable y su VME.
cat(sprintf("Si Desfavor. → %s: $%s\n", r_D$mejor, ...))
Imprime el proyecto óptimo si la información es
desfavorable y su VME.
cat(sprintf("VME con info imperfecta: $%s\n", ...))
Imprime el VME esperado considerando la información
imperfecta de la consultora.
cat(sprintf("VEII = $%s (máx a pagar por la consultora)\n", ...))
Imprime el Valor Esperado de la Información Perfecta
(VEII), indicando el máximo que se debería pagar por la
consultora.
# ---- Gráfico: VME por alternativa en cada escenario ----
df_vme <- data.frame(
Alternativa = rownames(pagos),
Sin_info = r_prior$vme,
Favorable = r_F$vme,
Desfavorable = r_D$vme
)
df_long <- pivot_longer(df_vme, -Alternativa,
names_to="Escenario", values_to="VME")
df_long$Escenario <- factor(df_long$Escenario,
levels=c("Sin_info","Favorable","Desfavorable"),
labels=c("Sin info","Favorable","Desfavorable"))
ggplot(df_long, aes(x=Alternativa, y=VME/1000, fill=Escenario)) +
geom_col(position="dodge", width=0.65) +
geom_hline(yintercept=0, color="gray50") +
geom_text(aes(label=paste0("$",round(VME/1000),"k"),
y=VME/1000+ifelse(VME>0,7,-15)),
position=position_dodge(0.65), size=2.8, fontface="bold") +
scale_fill_manual(values=c("Sin info"="#3a7fbd",
Favorable="#0f7a52",
Desfavorable="#b0305a")) +
labs(title="VME por Alternativa según Escenario de Información — TechParts",
subtitle="La información bayesiana cambia cuál alternativa es óptima",
x="Alternativa", y="VME (miles $)", fill="Escenario") +
theme_minimal() + theme(legend.position="top")
## Visualización del VME
Se construye un gráfico de barras que compara el VME de cada alternativa según el escenario de información:
df_vme <- data.frame(...)
Crea un data frame con el VME de cada alternativa para
los escenarios: sin información, favorable y desfavorable.
df_long <- pivot_longer(df_vme, -Alternativa, names_to="Escenario", values_to="VME")
Convierte el data frame a formato largo, adecuado para
ggplot.
df_long$Escenario <- factor(df_long$Escenario, levels=c(...), labels=c(...))
Ordena y etiqueta los niveles de escenario para el
gráfico.
ggplot(df_long, aes(x=Alternativa, y=VME/1000, fill=Escenario)) + geom_col(...)
Crea un gráfico de barras agrupadas mostrando el VME en
miles de dólares según la alternativa y el escenario.
geom_hline(yintercept=0, color="gray50")
Agrega una línea horizontal en 0 para referencia visual.
geom_text(aes(label=paste0("$",round(VME/1000),"k"), ...))
Muestra etiquetas de valor sobre cada barra, ajustando
la posición según sea positivo o negativo.
scale_fill_manual(values=c(...))
Asigna colores específicos a cada escenario para mayor claridad
visual.
labs(title=..., subtitle=..., x=..., y=..., fill=...)
Agrega título, subtítulo, etiquetas de ejes y leyenda
al gráfico.
theme_minimal() + theme(legend.position="top")
Aplica un tema limpio y coloca la leyenda arriba del
gráfico.
#Árbol de decisión
library(DiagrammeR)
# Valores del ejemplo calculado
# (reemplaza estos vectores con tus valores exactos si son distintos)
r_prior_vme <- r_prior$vme
r_F_vme <- r_F$vme
r_D_vme <- r_D$vme
# Árbol bayesiano teóricamente correcto
library(DiagrammeR)
# Supongamos estos valores de ejemplo (reemplaza con tus valores exactos)
r_prior_vme <- c(500000, 300000, 150000) # sin info
r_F_vme <- c(500000, 300000, 150000) # info favorable
r_D_vme <- c(500000, 300000, 150000) # info desfavorable
bF_prob <- 0.4
bD_prob <- 0.6
grViz("
digraph techparts {
graph [layout = dot, rankdir=LR, nodesep=0.6, ranksep=1]
# ===================== NODOS DE DECISIÓN =====================
D0 [label='Decisión Inicial\n(consultar o no)', shape=box, style=filled, fillcolor='#4A90E2', fontcolor=white]
D1 [label='Decisión Info Favorable\n(max VME posterior)', shape=box, style=filled, fillcolor='#4A90E2', fontcolor=white]
D2 [label='Decisión Info Desfavorable\n(max VME posterior)', shape=box, style=filled, fillcolor='#4A90E2', fontcolor=white]
# ===================== NODOS DE AZAR =====================
C1 [label='Resultado Consultora', shape=circle, style=filled, fillcolor='#F5A623']
C2 [label='Mercado sin info', shape=circle, style=filled, fillcolor='#F5A623']
# ===================== TERMINALES =====================
node [shape=box, style=filled, fillcolor='#7ED321', fontcolor=black]
# Sin consultora
S1 [label='Grande\n$500,000'] # máximo VME prior
S2 [label='Mediana\n$300,000']
S3 [label='Pequeña\n$150,000']
# Con info favorable
F1 [label='Grande\n$500,000'] # máximo VME posterior favorable
F2 [label='Mediana\n$300,000']
F3 [label='Pequeña\n$150,000']
# Con info desfavorable
D1_T [label='Grande\n$500,000']
D2_T [label='Mediana\n$300,000'] # máximo VME posterior desfavorable
D3_T [label='Pequeña\n$150,000']
# ===================== RANKS =====================
{ rank = same; D0 }
{ rank = same; C1; C2 }
{ rank = same; D1; D2 }
{ rank = same; S1; S2; S3; F1; F2; F3; D1_T; D2_T; D3_T }
# ===================== CONEXIONES =====================
# Decisión inicial
D0 -> C2 [label='No consultar']
D0 -> C1 [label='Consultar']
# Nodo azar mercado si no se consulta
C2 -> S1 [label='Grande', style=solid]
C2 -> S2 [label='Mediana', style=solid]
C2 -> S3 [label='Pequeña', style=solid]
# Nodo azar consultora
C1 -> D1 [label='Info Favorable\np=0.4']
C1 -> D2 [label='Info Desfavorable\np=0.6']
# Decisión posterior info favorable
D1 -> F1 [label='Elegir Grande']
D1 -> F2 [label='Poda', style=dashed]
D1 -> F3 [label='Poda', style=dashed]
# Decisión posterior info desfavorable
D2 -> D1_T [label='Poda', style=dashed]
D2 -> D2_T [label='Elegir Mediana']
D2 -> D3_T [label='Poda', style=dashed]
}
")
Conclusión final
ecisión final: No conviene contratar la consultora, porque lanzar directamente el proyecto con mayor VME prior (Grande) da un mayor valor esperado.
La rama “No consultar → Grande” es la rama óptima viva del árbol. Todas las demás ramas se podan (dashed) según la regla de maximización.