Generación de Variables Aleatorias · Tema 35

Distribuciones desde datos

De histogramas a generadores: sortear el bin por su peso y uniforme adentro, con k bien elegido.

01 · Punto de partida

Del retrato al molde

El Tema 34 remuestrea datos tal cual; este tema construye un modelo generativo con ellos: el histograma como densidad escalonada. Con 60 mediciones de demanda (media 4,59) armamos bines, pesamos cada uno y generamos miles de escenarios con la misma forma… y con colas donde el remuestreo no llega.

La receta es de dos pasos: bin por peso + uniforme adentro. El parámetro que todo lo decide es k, el número de bines.

  • ¿Cómo se sortea un bin con prob. cⱼ/n?
  • ¿Qué k elegir con n = 60: 4, 7 o 20?
  • ¿Qué gana el histograma frente al remuestreo crudo?
  • ¿Cómo se audita el modelo contra los datos?

02 · Definición

Bines, pesos y uniforme adentro

Con bordes e₀ < … < e_k: f(x) = cⱼ/(n·hⱼ) en el bin j de ancho hⱼ. La acumulada es lineal por tramos; invertirla es elegir bin por acumulada de pesos y luego uniforme. Reglas de k: Sturges 1+log₂n, raíz √n, Freedman-Diaconis por IQR.

J~c/n

Bin por peso

Inversión discreta sobre los k pesos (Tema 2): un U elige el tramo con la frecuencia observada.

U∈bin

Parejo adentro

El segundo U reparte uniforme en el bin: supone densidad plana local, la hipótesis más honesta sin más datos.

k≈7

k manda

Pocos bines ⇒ bloques toscos; muchos ⇒ picos ruidosos que memorizan. Con n = 60, k ≈ 7 equilibra.

Reglas de k con n = 60: todas apuntan al mismo barrio.
ReglakLectura
Sturges 1+log₂n≈ 7La defecto del laboratorio
Raíz √n≈ 8Similar, un poco más fina
k = 2020Memoriza: bines de 3 datos con huecos falsos

03 · Anatomía

Bordes, colas y costo

Bordes fijos una vez
Calcular [mín, máx] y acumulada de pesos una sola vez: cada muestra cuesta 2 U (bin + adentro) y una búsqueda que con k chico es lineal.
Bines vacíos intermedios
Peso 0 ⇒ jamás salen: el modelo respeta huecos reales como la empírica discreta, sin inventar como la interpolada.
Cola más allá del máx
El histograma muere en el máximo observado. Para escenarios extremos, pegar una cola paramétrica (exponencial) al último bin o ajustar modelo (abajo).
Alternativa paramétrica
Ajustar normal por momentos (μ̂ = x̄, σ̂ = s) genera colas infinitas con 2 parámetros: menos fiel al cuerpo, mejor en colas. Comparar por KS.

Histograma k ≈ 7

Fiel y continuo

Reproduce modas y asimetrías sin suponer familia; genera valores nuevos dentro del rango.

Remuestreo crudo

Exacto pero discreto

Solo repite los 60 valores: perfecto para bootstrap (Tema 30), pobre como escenario continuo.

04 · Dónde se modela a medida

Del retrato al escenario

datos n→histograma k→bin + U
  1. 1
    Demanda y plazos.

    Escenarios de simulación con la forma real cuando ninguna familia ajusta.

  2. 2
    Datos sintéticos.

    Compartir forma sin exponer filas: el histograma agrega y anonimiza.

  3. 3
    Mezclas a ojo.

    Un histograma bimodal modela dos poblaciones sin estimar mezclas formales.

  4. 4
    Puente a validación.

    Modelo contra datos con KS y chi: el Tema 36 juzga este molde.

05 · Representación en Python

Histograma k = 7 que genera

60 demandas fijas: bines equipaciados, acumulada de pesos y doble uniforme por muestra, con KS contra la empírica.

Python en tu navegador. Llevá k a 20: el KS empeora por memorización.

import random
import bisect

random.seed(310)
datos = [3.1,4.4,5.0,2.6,4.3,8.0,3.2,4.2,5.1,2.2,4.8,6.1,4.7,3.4,
 5.0,3.9,5.2,4.9,4.8,3.9,6.8,5.3,5.8,5.3,4.7,5.6,5.2,5.4,5.3,4.6,
 5.3,5.4,6.3,4.2,6.4,2.1,3.8,5.0,4.3,5.6,3.8,8.8,3.4,4.8,6.4,5.5,
 4.2,3.6,2.2,2.9,5.8,3.2,4.3,2.6,3.7,2.5,5.1,5.4,2.0,4.2]
n, k, N = len(datos), 7, 8000
lo, hi = min(datos), max(datos)
w = (hi - lo) / k
conteo = [0]*k
for x in datos:
    conteo[min(int((x-lo)/w), k-1)] += 1
acum = []
s = 0.0
for c in conteo:
    s += c/n
    acum.append(s)

def histograma():
    u = random.random()
    j = bisect.bisect_left(acum, u)
    return lo + (j + random.random())*w

m = [histograma() for _ in range(N)]
print("media datos:", round(sum(datos)/n, 3), "gen:", round(sum(m)/N, 3))
print("bins:", conteo)

Media ≈ 4,59 en ambas y bines que copian la forma: el cuerpo lleno, la cola casi vacía.

06 · Exploración

Laboratorio: k que afina o memoriza

Movete k y N sobre las 60 demandas. Las barras son el sintético; los rombos, el peso del bin (por construcción calzan: lo que se juzga es la forma). El KS del panel compara sintético contra datos crudos.

EXPERIMENTO 35

Histograma generativo

J ~ c/n · X|J ~ U(bin)

Los resultados numéricos aparecen debajo.
Media gen.4,593
Media datos4,593
D KS0,071
Bines vacíos1

Con k 7 y N 6000, forma fiel y KS ≈ 0,07.

Barras del sintético vs rombos del peso. Probá k = 3 (bloques) y k = 20 (islas).

Preguntas para explorar

  1. Con k = 7, ¿KS chico? ¿Bines vacíos?
  2. Bajá a k = 3. ¿La forma se vuelve bloques? ¿El KS sube?
  3. Subí a k = 20. ¿Aparecen bines vacíos intermedios? ¿El KS también sube?
Ver respuestas sugeridas
  1. Sí: KS ≈ 0,07 y 1 vacío (la cola entre 6,9 y 7,8, real: solo 8,0 y 8,8 más allá).
  2. Sí: 3 bloques borran la moda y la cola; el KS trepa a ≈ 0,13 por sesgo.
  3. Trampa: el KS in-sample baja a ≈ 0,05, pero aparecen vacíos intermedios e islas — memoriza ruido y el KS contra los propios datos no lo castiga.

07 · Comprensión

Confusiones frecuentes

«Más bines, mejor modelo»

Hasta el punto de memorización: con k = n cada bin tiene 1 dato y el “modelo” es el remuestreo con jitter. Los bines vacíos y las islas lo delatan, no el KS in-sample.

«El uniforme adentro no importa»

Sin él (devolver el centro del bin) el sintético es discreto de k valores: grumos artificiales cada w unidades.

«Los bordes se estiman por muestra»

No: [mín, máx] fijos del ajuste. Reestimarlos por réplica mueve el soporte y rompe la acumulada.

«KS chico = modelo verdadero»

KS chico dice “compatible”, no “verdadero”: con n = 60, varios k distintos pasan el test. Elegir el más simple.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: molde auditado

Datos del tema, k = 7, N = 8000 (semilla 311): media ≈ 4,59 y KS < 0,10.

import random
import bisect

random.seed(311)
datos = [3.1,4.4,5.0,2.6,4.3,8.0,3.2,4.2,5.1,2.2,4.8,6.1,4.7,3.4,
 5.0,3.9,5.2,4.9,4.8,3.9,6.8,5.3,5.8,5.3,4.7,5.6,5.2,5.4,5.3,4.6,
 5.3,5.4,6.3,4.2,6.4,2.1,3.8,5.0,4.3,5.6,3.8,8.8,3.4,4.8,6.4,5.5,
 4.2,3.6,2.2,2.9,5.8,3.2,4.3,2.6,3.7,2.5,5.1,5.4,2.0,4.2]
n, k, N = len(datos), 7, 8000
lo, hi = min(datos), max(datos)
w = (hi-lo)/k
conteo = [0]*k
for x in datos:
    conteo[min(int((x-lo)/w), k-1)] += 1
acum, s = [], 0.0
for c in conteo:
    s += c/n
    acum.append(s)
m = [lo+(bisect.bisect_left(acum, random.random())+random.random())*w
     for _ in range(N)]
print(round(sum(m)/N, 3), "vs 4.593")
Ver solución razonada

≈ 4,59 ± 0,05. Si la media da ≈ 5,4, los bordes se calcularon sobre otra escala.

Ejercicio 2: k que sesga vs k que memoriza

Compará el KS con k = 3, 7 y 20 (N = 6000): k = 3 sesga, k = 20 memoriza aunque su KS in-sample sea menor.

import random
import bisect

random.seed(312)
datos = [3.1,4.4,5.0,2.6,4.3,8.0,3.2,4.2,5.1,2.2,4.8,6.1,4.7,3.4,
 5.0,3.9,5.2,4.9,4.8,3.9,6.8,5.3,5.8,5.3,4.7,5.6,5.2,5.4,5.3,4.6,
 5.3,5.4,6.3,4.2,6.4,2.1,3.8,5.0,4.3,5.6,3.8,8.8,3.4,4.8,6.4,5.5,
 4.2,3.6,2.2,2.9,5.8,3.2,4.3,2.6,3.7,2.5,5.1,5.4,2.0,4.2]
n, N = len(datos), 6000
def ks(k):
    lo, hi = min(datos), max(datos)
    w = (hi-lo)/k
    conteo = [0]*k
    for x in datos:
        conteo[min(int((x-lo)/w), k-1)] += 1
    acum, s = [], 0.0
    for c in conteo:
        s += c/n
        acum.append(s)
    m = sorted(lo+(bisect.bisect_left(acum, random.random())+random.random())*w
               for _ in range(N))
    return max(abs((i+1)/N - sum(1 for d in datos if d <= x)/n)
               for i, x in enumerate(m))
print("k=3:", round(ks(3), 3), "k=7:", round(ks(7), 3), "k=20:", round(ks(20), 3))
Ver solución

k = 3 sesga (≈ 0,13), k = 7 equilibra (≈ 0,07) y k = 20 memoriza: su KS in-sample baja (≈ 0,05) pero parte la densidad en islas con vacíos. El KS contra los propios datos no castiga memorizar.

Ejercicio 3: rival paramétrico

Ajustá N(x̄, s) por momentos y compará su KS contra el histograma k = 7: ¿quién gana en el cuerpo?

Ver una posible respuesta
import random
import math

random.seed(313)
datos = [3.1,4.4,5.0,2.6,4.3,8.0,3.2,4.2,5.1,2.2,4.8,6.1,4.7,3.4,
 5.0,3.9,5.2,4.9,4.8,3.9,6.8,5.3,5.8,5.3,4.7,5.6,5.2,5.4,5.3,4.6,
 5.3,5.4,6.3,4.2,6.4,2.1,3.8,5.0,4.3,5.6,3.8,8.8,3.4,4.8,6.4,5.5,
 4.2,3.6,2.2,2.9,5.8,3.2,4.3,2.6,3.7,2.5,5.1,5.4,2.0,4.2]
n, N = len(datos), 6000
mu = sum(datos)/n
s = (sum((x-mu)**2 for x in datos)/n) ** 0.5
m = sorted(random.gauss(mu, s) for _ in range(N))
Phi = lambda z: 0.5*(1+math.erf(z/math.sqrt(2)))
print("KS normal:", round(max(abs((i+1)/N - Phi((x-mu)/s))
      for i, x in enumerate(m)), 3))

La normal da ≈ 0,02–0,03: compite bien porque los datos son casi campana con cola. Con bimodalidad real, el histograma la duplica.

09 · Síntesis

Ideas para recordar

  • Histograma: bin por peso cⱼ/n + uniforme adentro, 2 U por muestra.
  • k ≈ Sturges/√n; ni bloques ni islas.
  • Bines vacíos respetan huecos; la cola muere en el máx.
  • Auditar con media + KS contra datos crudos.
  • Rival paramétrico por momentos para colas.

En el próximo tema el juicio final: comparar generado contra teórica.