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.
| Fase | Q | N |
|---|---|---|
| Gruesa | 60–140 cada 10 | 3 000 c/u, mismas semillas |
| Fina | 90–110 cada 5 | 10 000 c/u |
| Confirmar | Ganador | 20 000, semilla nueva |
03 · Método
- 1Barrer grueso.
Toda la grilla con N moderado y mismas demandas. Descartar colas.
- 2Filtrar top + empates.
Pasan el mejor y los que empaten a 1–2SE. No coronar por centésimas.
- 3Zoom 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
- 1Diariero.
Gruesa corona 100; fina confirma 100 sobre 95/105.
- 2Precio.
Grilla 4/5/6 con demandas comunes: 6 gana si la demanda aguanta.
- 3K 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.
Buscar entre ruido
Q̂* = argmax media(Q)
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
- Con N = 300, ¿cuántas veces de 5 gana 100?
- ¿Qué N estabiliza el podio?
- ¿Por qué confirmar con semilla nueva?
Ver respuestas sugeridas
- ~2 de 5: el resto corona vecinos por suerte.
- ~3 000–5 000: SE ≈ 2–3 frente a gaps de 10–20.
- 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.