01 · Punto de partida
Sin repetición no hay ciencia
En el Tema 5 aprendiste que la semilla decide la historia. Ahora la convertimos en método: un experimento de simulación solo existe si otro puede repetirlo y obtener lo mismo. «Me dio 0,62» sin semilla, sin código versionado y sin N es una anécdota, no un resultado.
La buena noticia es que con PRNGs la reproducibilidad es barata: basta disciplinar la siembra. La mala es que es frágil: un solo random.random() sin sembrar, un shuffle olvidado o un timestamp escondido bastan para romperla.
- ¿Qué significa «repetir bit a bit» y qué nivel te exigen?
- ¿Qué 5 datos tenés que guardar sí o sí?
- ¿Dónde se esconden los azarosos no controlados?
- ¿Cómo demostrás que tu corrida es repetible?
02 · Definición
Niveles y contrato de reproducibilidad
Para programadores alcanza con tres niveles prácticos:
Repetible
Vos mismo, en tu máquina, corrés dos veces y da idéntico. Es el piso: si ni vos repetís, nadie más podrá.
Reproducible
Otro, con tu código + semillas + versiones, obtiene lo mismo en su máquina. Es el estándar de este curso y de un paper serio.
Robusto
Pequeños cambios (otra semilla del mismo protocolo) dan conclusiones compatibles. Anticipa los Temas 36–38: no overfitear una semilla.
| Dato | Ejemplo | Sin esto… |
|---|---|---|
| Semilla(s) | seed = 2026 | La secuencia es fantasma |
| Código + versión | sim-v1.2, commit a3f9 | La fórmula pudo cambiar |
| Parámetros y N | a, c, m, N = 10 000 | Comparás peras con manzanas |
| Entorno relevante | Python 3.12, random | Otro generador da otra historia |
03 · Protocolo
El protocolo de 5 líneas
Todo experimento del curso seguirá este ritual. Pegalo en tu cuaderno:
- 1. Sembrar una vez
- Al inicio del programa, una sola vez:
random.seed(SEED). Nunca dentro de un loop ni por tiro. - 2. Registrar
- Imprimí y guardá
SEED, parámetros,Ny versión antes de correr. Lo que no se imprime, se pierde. - 3. Aislar
- Todo azar pasa por el generador sembrado. Nada de
time,os.urandomnishufflesuelto en medio de la simulación. - 4. Repetir en frío
- Volvé a correr desde cero con el mismo registro y compará bit a bit (o por hash). Debe dar idéntico.
- 5. Variar con método
- Para réplicas, usá lista explícita de semillas
[101, 102, 103], no «correr sin seed varias veces».
Corrida seria
Trazable
Un diccionario EXPERIMENTO acompaña cada salida. Cualquiera repite con copiar-pegar.
Corrida fantasma
Irrepetible
Semilla implícita del sistema, parámetros en la cabeza, N a ojo. Ni el autor la repite una semana después.
04 · Ejemplos
Dónde duele no ser reproducible
- 1Depuración.
Un valor atípico en la corrida 8 432 solo se inspecciona si podés rebobinar hasta él con la misma semilla.
- 2Comparación justa.
Dos políticas de stock se comparan con las mismas semillas (números comunes): si cada una usa azar distinto, no sabés qué ganó.
- 3Publicación.
Paper sin semillas ni código es fe ciega. Con registro completo, el revisor repite en su máquina.
- 4Clase.
El docente fija semilla y todos ven lo mismo; cada alumno varía con su semilla asignada sin perder el marco común.
05 · Patrón en Python
Experimento empaquetado
Este esqueleto te servirá hasta el proyecto final (Tema 45): todo azar cuelga de SEED y todo queda registrado.
Python en tu navegador. Ejecutalo dos veces: debe dar idéntico. Cambiá la semilla y debe cambiar de forma controlada.
import random
EXPERIMENTO = {"semilla": 2026, "n": 1000, "version": "t6-v1"}
random.seed(EXPERIMENTO["semilla"])
vals = [random.random() for _ in range(EXPERIMENTO["n"])]
media = sum(vals) / len(vals)
print(EXPERIMENTO)
print("media:", round(media, 5))
La media debe repetirse exacta entre ejecuciones. Si no, hay un azaroso fuera del protocolo.
Réplicas con lista explícita
Así se comparan escenarios sin trampa: cada réplica tiene su semilla declarada.
import random
SEMILLAS = [101, 102, 103]
for s in SEMILLAS:
random.seed(s)
vals = [random.random() for _ in range(500)]
print(s, round(sum(vals) / len(vals), 5))
06 · Exploración
Laboratorio: gemelas idénticas vs. vecinas distintas
El laboratorio corre el mismo experimento dos veces: la corrida A siempre usa tu semilla; la B usa la misma semilla o la siguiente según el interruptor. Las curvas son medias acumuladas: si B repite semilla, se superponen perfecto.
Repetir o variar a voluntad
misma seed → misma media(n)
Con la misma semilla la diferencia debe ser cero exacta.
Cada línea es la media acumulada hasta n. La superposición exacta demuestra reproducibilidad bit a bit.
Preguntas para explorar
- Con misma semilla y N = 2000, ¿la diferencia final es exactamente 0? ¿Por qué es importante que sea 0 y no «casi 0»?
- Cambiá B a A+1: ¿las curvas se separan al inicio o solo al final? ¿Qué dice eso de «parecido» vs «idéntico»?
- Si publicaras solo la media sin semilla, ¿podría otro saber si tu 0,502 vino de A o de B?
Ver respuestas sugeridas
- Sí, 0 exacto: mismo cálculo, mismos bits. «Casi 0» sería coincidencia; 0 es garantía de protocolo.
- Se separan desde los primeros valores: son historias distintas aunque ambas parezcan azar. Promedios cercanos no implican misma secuencia.
- No: medias cercanas son indistinguibles sin semilla. El dato sin semilla no es verificable.
07 · Comprensión
Confusiones frecuentes
«Reproducible es que dé parecido»
No: reproducible es idéntico bit a bit con mismo registro. «Parecido» es variabilidad entre réplicas, que se estudia aparte con varias semillas.
«Sembré una vez al inicio del notebook y listo»
En notebooks, reejecutar celdas fuera de orden resiembra o salta estados sin que lo notes. Reiniciá el kernel y corré de arriba abajo para verificar.
«Solo usé random, así que estoy cubierto»
Si además usaste numpy, shuffle de otro import o hash() aleatorio, hay azarosos fuera de tu seed. Todo generador se siembra.
«Cambio la semilla para arreglar un mal resultado»
Elegir la semilla que «da lindo» es p-hacking con otro nombre. Las semillas se fijan antes, se listan todas y se reportan todas (Tema 36).
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: demostrar el contrato
Corrida A y corrida B con el mismo registro deben coincidir; con semilla distinta, diferir.
import random
def corrida(semilla, n=200):
random.seed(semilla)
return [random.random() for _ in range(n)]
a = corrida(42)
b = corrida(42)
c = corrida(43)
print("a == b:", a == b)
print("a == c:", a == c)
Ver solución razonada
a == b es True exacto; a == c es False. Esa es la firma del protocolo funcionando.
Ejercicio 2: cazar el azaroso fantasma
Este código parece reproducible pero no lo es. ¿Dónde está el azar no sembrado?
import random
import time
random.seed(1)
print(random.random())
print(time.time() % 1)
Ver solución
La segunda línea usa el reloj, no el PRNG sembrado: cambia en cada corrida aunque la semilla sea fija. Todo lo que varíe debe salir del generador controlado.
Ejercicio 3: hash de verificación
Guardá un hash corto de tu secuencia para verificar repetición sin comparar listas enteras.
Ver una posible respuesta
import hashlib
import random
random.seed(2026)
vals = [random.random() for _ in range(1000)]
h = hashlib.sha256(str(vals).encode()).hexdigest()[:12]
print("hash:", h)
Repetí en frío: el hash debe coincidir carácter por carácter. Es como el checksum de tu experimento.
09 · Síntesis
Ideas para recordar
- Reproducible = idéntico, no parecido; se verifica con igualdad exacta o hash.
- El contrato guarda semilla, código/versión, parámetros, N y entorno.
- Se siembra una vez al inicio; todo azar sale del generador sembrado.
- Las réplicas usan lista explícita de semillas, nunca «sin seed varias veces».
- Un azaroso escondido (tiempo, shuffle, numpy sin seed) rompe todo.
En el próximo tema definiremos qué le exigimos a un generador para confiar en él: las propiedades deseables de un generador (uniformidad, independencia y período).