Números Pseudoaleatorios · Tema 06

Reproducibilidad mediante semillas

El protocolo para repetir un experimento bit a bit: qué guardar junto a la semilla y cómo evitar los azarosos fantasmas que arruinan réplicas.

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.

Contrato mínimo de una corrida.
DatoEjemploSin esto…
Semilla(s)seed = 2026La secuencia es fantasma
Código + versiónsim-v1.2, commit a3f9La fórmula pudo cambiar
Parámetros y Na, c, m, N = 10 000Comparás peras con manzanas
Entorno relevantePython 3.12, randomOtro 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, N y 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.urandom ni shuffle suelto 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

Detectar raro→Repetir idéntico→Corregir y publicar
  1. 1
    Depuración.

    Un valor atípico en la corrida 8 432 solo se inspecciona si podés rebobinar hasta él con la misma semilla.

  2. 2
    Comparació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ó.

  3. 3
    Publicación.

    Paper sin semillas ni código es fe ciega. Con registro completo, el revisor repite en su máquina.

  4. 4
    Clase.

    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.

EXPERIMENTO 06

Repetir o variar a voluntad

misma seed → misma media(n)

Los resultados numéricos aparecen debajo.
Media A—
Media B—
Diferencia |A−B|—
Veredicto—

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

  1. Con misma semilla y N = 2000, ¿la diferencia final es exactamente 0? ¿Por qué es importante que sea 0 y no «casi 0»?
  2. Cambiá B a A+1: ¿las curvas se separan al inicio o solo al final? ¿Qué dice eso de «parecido» vs «idéntico»?
  3. Si publicaras solo la media sin semilla, ¿podría otro saber si tu 0,502 vino de A o de B?
Ver respuestas sugeridas
  1. Sí, 0 exacto: mismo cálculo, mismos bits. «Casi 0» sería coincidencia; 0 es garantía de protocolo.
  2. Se separan desde los primeros valores: son historias distintas aunque ambas parezcan azar. Promedios cercanos no implican misma secuencia.
  3. 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).