Método de Monte Carlo · Tema 40

Optimización mediante simulación

Buscar el mejor Q entre ruido: grilla gruesa, mismas semillas y zoom final.

01 · Punto de partida

Optimizar es comparar con ruido

Cada Q tiene una media con ±. Elegir el máximo muestral sin mirar el ± es coronar al más suertudo. Optimizar por simulación es barrer con mismas semillas, medir con IC y refinar alrededor del mejor.

En estática de una variable basta grilla + zoom; el ruido se domestica con N y bloques.

  • ¿Qué variable optimizo y en qué rango?
  • ¿Con qué N comparo sin que el ruido mande?
  • ¿El ganador gana en todos los bloques?
  • ¿Hago zoom o me quedo?

02 · Definición

Ruido, sesgo de selección y remedio

📊

Grilla

Q candidatos equiespaciados: 60–140 cada 10. Cubre sin explotar.

🏆

Sesgo del ganador

El máximo muestral sobreestima: ganó con ayuda del ruido. Se corrige confirmando.

🔍

Zoom

Grilla fina alrededor del top con más N y semilla nueva.

Protocolo del diariero.
FaseQN
Gruesa60–140 cada 103 000 c/u, mismas semillas
Fina90–110 cada 510 000 c/u
ConfirmarGanador20 000, semilla nueva

03 · Método

Barrer→Filtrar→Zoom
  1. 1
    Barrer grueso.

    Toda la grilla con N moderado y mismas demandas. Descartar colas.

  2. 2
    Filtrar top + empates.

    Pasan el mejor y los que empaten a 1–2SE. No coronar por centésimas.

  3. 3
    Zoom y confirmar.

    Fina con más N y confirmación del ganador con semilla nueva.

Maldición del ganador
El mejor muestral está inflado: confirmarlo con datos nuevos lo desinfla a lo real.
Diferencias pareadas
Comparar dif_s por bloque, no medias sueltas: menos varianza, mejor ranking.
Parada
Parar cuando el top-2 empata dentro de e irrelevante ($2): más N no decide nada útil.

04 · Ejemplos

  1. 1
    Diariero.

    Gruesa corona 100; fina confirma 100 sobre 95/105.

  2. 2
    Precio.

    Grilla 4/5/6 con demandas comunes: 6 gana si la demanda aguanta.

  3. 3
    K de call.

    No se optimiza solo: precio vs riesgo (frontera, no máximo).

05 · Representación en Python

Grilla con demandas comunes

Python en tu navegador. Una lista de D para todos los Q.

import random

random.seed(7)
Ds = random.choices([80, 100, 120], weights=[30, 40, 30], k=8000)
Qs = list(range(60, 141, 10))
meds = {Q: sum(5*min(Q, D)-2*Q for D in Ds)/len(Ds) for Q in Qs}
top = max(meds, key=meds.get)
print("ganador gruesa:", top, round(meds[top], 1))
finos = list(range(top-10, top+11, 5))
meds2 = {Q: sum(5*min(Q, D)-2*Q for D in Ds)/len(Ds) for Q in finos}
print("ganador fina:", max(meds2, key=meds2.get))

06 · Exploración

Laboratorio: el ruido corrompe el podio

Curva blanca exacta con óptimo ★ en 100. Puntos verdes: tus estimaciones ruidosas con N por Q. Con N chico corona cualquiera; con N grande, al real.

EXPERIMENTO 40

Buscar entre ruido

Q̂* = argmax media(Q)

Los resultados numéricos aparecen debajo.
Q real100
Q hallado—
Acierto—
Lectura—

Tocá «Barrer» para optimizar con ruido.

Con N = 300 el ganador rota entre 80–120. Con N = 10 000 se clava en 100. El ruido elige si lo dejás.

Preguntas para explorar

  1. Con N = 300, ¿cuántas veces de 5 gana 100?
  2. ¿Qué N estabiliza el podio?
  3. ¿Por qué confirmar con semilla nueva?
Ver respuestas sugeridas
  1. ~2 de 5: el resto corona vecinos por suerte.
  2. ~3 000–5 000: SE ≈ 2–3 frente a gaps de 10–20.
  3. Para desinflar la maldición del ganador: con datos nuevos el campeón prueba que es real.

07 · Comprensión

Confusiones frecuentes

«El máximo muestral es el óptimo»

Es el candidato: confirmarlo con más N y otra semilla antes de coronar.

«Grilla fina desde el inicio»

Quema N en colas. Gruesa → fina es 5× más barato.

«Cada Q con sus demandas»

El ranking tiembla de más. Mismas demandas para todos.

«Empate a 1 $ pide más N»

Si e relevante es $5, empatan y se elige por servicio o costo. No todo empate pide N.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: podio ruidoso

Barré con N = 400 y mirá quién gana 3 veces.

import random

for intento in range(3):
    Ds = [random.choices([80,100,120], weights=[30,40,30])[0] for _ in range(400)]
    meds = {Q: sum(5*min(Q,D)-2*Q for D in Ds)/len(Ds) for Q in [80,100,120]}
    print(max(meds, key=meds.get))
Ver solución razonada

Rotará entre 80/100/120: con N = 400 el SE ≈ 8 tapa gaps de 20.

Ejercicio 2: podio estable

Repetí con N = 8 000 y demandas comunes.

import random

random.seed(11)
Ds = random.choices([80,100,120], weights=[30,40,30], k=8000)
print(max([80,100,120], key=lambda Q: sum(5*min(Q,D)-2*Q for D in Ds)))
Ver solución

100 estable: SE ≈ 2 frente a gaps de 20–50.

Ejercicio 3: confirmar al campeón

Confirmá Q = 100 con otra semilla y N = 15 000.

Ver una posible respuesta
import random

for s in [99, 100]:
    random.seed(s)
    Ds = random.choices([80,100,120], weights=[30,40,30], k=15000)
    m = sum(5*min(100,D)-200 for D in Ds)/len(Ds)
    print(s, round(m, 1))

~290 en ambas: campeón confirmado, no suertudo.

09 · Síntesis

Ideas para recordar

  • Grilla gruesa con mismas semillas, top + empates, zoom fino, confirmación nueva.
  • El máximo muestral está inflado: confirmar desinfla.
  • N por Q según gaps: SE menor que la mitad del gap.
  • Empate dentro de e relevante se decide por criterio, no por N.
  • Una lista de D para todos los Q.

En el próximo tema aceleraremos con núcleos: la paralelización de simulaciones.