Generación de Variables Aleatorias · Tema 06

Inversión analítica

Cómo despejar Q(u) de u = F(x) con fórmula cerrada: Weibull, Pareto, logística, Cauchy y triangular, con verificación y costo por muestra.

01 · Punto de partida

Cuando la inversa cabe en una línea

La transformada inversa (Tema 5) es general, pero solo es “barata” si Q(u) tiene fórmula cerrada: un logaritmo, una potencia, una raíz. Este tema es el recetario de esas Q: cómo se deducen, cómo se verifican y cuánto cuestan.

Si tu distribución está en este catálogo, el generador es una función de 1–2 operaciones. Si no está (normal, gamma general, beta), no la fuerces: va numérica (Tema 7) o método dedicado.

  • ¿Cómo se despeja x de u = F(x) sin memorizar?
  • ¿Qué verificaciones evitan un signo o una rama mal elegida?
  • ¿Log, potencia o raíz: qué cuesta cada una por millón de muestras?
  • ¿Qué Q conviene memorizar de por vida?

02 · Definición

El despeje universal en 3 pasos

Sea u = F(x). Entonces: 1) aislar el término con x, 2) aplicar la inversa (log, potencia, tan), 3) despejar x. Ejemplo guía con Weibull F(x) = 1 − exp(−(x/λ)^k):

✎

Deducir

Aislar, invertir, despejar. Un error de signo en el log o de rama en la raíz arruina colas aunque la media “dé bien”.

✓

Verificar

Chequear Q(0⁺) = borde inferior, Q(1⁻) = borde superior, Q(F(x)) = x y que Q′ ≥ 0. Tres evaluaciones cazan el 90 % de bugs.

⏱

Costar

Un log ≈ una potencia ≈ decenas de sumas. Para N = 10⁷, elegir Q con una potencia en vez de tres sí se nota (Tema 39).

Catálogo mínimo de Q cerradas (U ~ U(0,1)).
X ~F(x)Q(u)
U(a,b)(x−a)/(b−a)a + (b−a)·u
Exp(λ)1 − e^(−λx)−ln(1−u)/λ
Weibull(λ,k)1 − exp(−(x/λ)^k)λ·(−ln(1−u))^(1/k)
Pareto(xm,α)1 − (xm/x)^αxm·(1−u)^(−1/α)
Logística(μ,s)1/(1+e^(−(x−μ)/s))μ − s·ln((1−u)/u)
Cauchy(x₀,γ)1/π·arctan((x−x₀)/γ)+1/2x₀ + γ·tan(π(u−1/2))

03 · Anatomía

Triangular: la Q por tramos bien hecha

La triangular(a,c,b) —mínimo a, moda c, máximo b— no tiene una sola fórmula sino dos ramas según de qué lado de la moda cae u. Sea Fc = (c−a)/(b−a):

Rama izquierda (u < Fc)
X = a + √[u·(b−a)·(c−a)]. Nace de u = (x−a)²/[(b−a)(c−a)].
Rama derecha (u ≥ Fc)
X = b − √[(1−u)·(b−a)·(b−c)]. Nace de 1−u = (b−x)²/[(b−a)(b−c)].
Continuidad en la moda
Ambas ramas dan c cuando u = Fc. Si tu código salta en la moda, mezclaste los anchos (c−a) y (b−c).
Costo
Una comparación + una raíz cuadrada. Más barata que un log y exacta, ideal para PERT y tiempos “optimista–más probable–pesimista”.

Q cerrada

Una evaluación, lista

Sin bucles, sin rechazos, sin tablas. La validación es solo Monte Carlo: con N grande calza por construcción.

Q inexistente

No inventar ramas

Normal, gamma no entera, beta: sin elemental. Intentar “aproximar Q con un polinomio a ojo” sesga colas; usar numérica o método dedicado.

04 · Cuándo usar cada una

Del modelo a la Q en 30 segundos

¿F despejable?→sí: Q cerrada→no: numérica / dedicado
  1. 1
    Tiempos y fallas.

    Exponencial (tasa constante) y Weibull (tasa creciente/decreciente según k). (Temas 22, 27)

  2. 2
    Riesgo y colas pesadas.

    Pareto para ingresos/ciudades/redes; Cauchy como contraejemplo sin media. Truncar con criterio.

  3. 3
    Opinión y duraciones acotadas.

    Triangular(a,c,b) y U(a,b) para “mín–moda–máx” cuando no hay datos para más. (Tema 27)

  4. 4
    Crecimiento logístico.

    Logística(μ,s): prima de la normal con Q elemental. Útil para testear código normal antes de Box-Muller.

05 · Representación en Python

Cinco Q en diez líneas

El mismo U alimenta cinco distribuciones. Cambiar de modelo es cambiar de Q, no de arquitectura.

Python en tu navegador. Verificá medianas: Weibull(λ=1,k=2) ≈ 0,833; Pareto(1,2) ≈ 1,414; logística(0,1) ≈ 0.

import random
import math

random.seed(40)

def Q_weibull(u, lam=1.0, k=2.0):
    return lam * (-math.log(1 - u)) ** (1 / k)

def Q_pareto(u, xm=1.0, alpha=2.0):
    return xm * (1 - u) ** (-1 / alpha)

def Q_logistica(u, mu=0.0, s=1.0):
    u = min(max(u, 1e-12), 1 - 1e-12)
    return mu - s * math.log((1 - u) / u)

def Q_cauchy(u, x0=0.0, gamma=1.0):
    u = min(max(u, 1e-12), 1 - 1e-12)
    return x0 + gamma * math.tan(math.pi * (u - 0.5))

def Q_triangular(u, a=0.0, c=2.0, b=5.0):
    Fc = (c - a) / (b - a)
    if u < Fc:
        return a + math.sqrt(u * (b - a) * (c - a))
    return b - math.sqrt((1 - u) * (b - a) * (b - c))

N = 6000
for nombre, Q in [("weibull", Q_weibull), ("pareto", Q_pareto),
                  ("logistica", Q_logistica), ("cauchy", Q_cauchy),
                  ("triangular", Q_triangular)]:
    m = sorted(Q(random.random()) for _ in range(N))
    print(nombre, "mediana ≈", round(m[N // 2], 3))

Esperado: weibull ≈ 0,83 · pareto ≈ 1,41 · logistica ≈ 0 · cauchy ≈ 0 (con extremos enormes) · triangular ≈ 2,1.

06 · Exploración

Laboratorio: Weibull que cambia de forma con k

Movete k con λ = 1 fijo. Con k < 1 la densidad explota en 0 (fallas infantiles); con k = 1 es exponencial; con k > 1 se concentra (desgaste). El histograma debe seguir a la curva teórica.

EXPERIMENTO 06

Inversión cerrada de Weibull

X = (−ln(1−U))^(1/k)

Los resultados numéricos aparecen debajo.
Mediana muestral0,833
Mediana teórica0,833
P(X>1) muestral0,368
P(X>1) teórica0,368

Con k 2, mediana 0,833 y cola 0,368.

Histograma en densidad hasta el percentil 99. Probá k = 0,5 (pico en cero) y k = 3 (campana asimétrica).

Preguntas para explorar

  1. Con k = 1, ¿a qué distribución colapsa? Verificá mediana ln 2 ≈ 0,693.
  2. Con k = 0,5, ¿por qué la primera barra es altísima? Mirá f(x) cerca de 0.
  3. Con N = 300, ¿la mediana sigue estable aunque el histograma esté ruidoso?
Ver respuestas sugeridas
  1. A Exp(1): Q = −ln(1−u), mediana −ln(0,5) = ln 2.
  2. Porque f(x) ∝ x^(−0,5)·e^(−√x) diverge en 0: área enorme pegada al origen.
  3. Sí, bastante: la mediana es robusta; las barras (densidad local) necesitan mucho más N.

07 · Comprensión

Confusiones frecuentes

«Despejo y listo, sin verificar»

El 80 % de los bugs son signo del log, base del exponente o rama de la triangular. El test Q(F(x₀)) = x₀ con 2–3 x₀ los caza en segundos.

«Uso U en vez de 1−U y “da parecido”»

En distribución da igual, pero numéricamente 1−U pierde precisión cuando U ≈ 1 (cola). Para colas derechas extremas preferí −ln(U), que preserva resolución.

«Cauchy tiene media 0 por simetría»

No tiene media (integral diverge). La media muestral salta sin converger: validá con mediana, no con promedio.

«Triangular con una sola rama»

Una sola raíz solo cubre medio soporte. Sin el if u < Fc la moda se desplaza y el histograma queda truncado.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: deducir Pareto sin mirar

Partí de F(x) = 1 − (1/x)² para x ≥ 1, despejá Q y validá la mediana √2 con 6000 muestras (semilla 41).

import random

random.seed(41)
N = 6000
m = sorted((1 - random.random()) ** (-1 / 2) for _ in range(N))
print(round(m[N // 2], 3), "vs", round(2 ** 0.5, 3))
Ver solución razonada

Despeje: u = 1 − x^(−2) ⇒ x = (1−u)^(−1/2). Mediana muestral ≈ 1,41. Si da ≈ 0,7, olvidaste el signo negativo del exponente.

Ejercicio 2: logística como “normal barata”

Generá 8000 logísticas(μ=10, s=2) y verificá mediana ≈ 10 y P(X > 12) = 1/(1+e^((12−10)/2)) ≈ 0,269.

import random
import math

random.seed(42)
mu, s, N = 10.0, 2.0, 8000
m = []
for _ in range(N):
    u = random.random()
    u = min(max(u, 1e-12), 1 - 1e-12)
    m.append(mu - s * math.log((1 - u) / u))
m_sorted = sorted(m)
print("mediana:", round(m_sorted[N // 2], 3))
print("cola:", round(sum(1 for x in m if x > 12) / N, 3), "vs", round(1 / (1 + math.exp(1)), 3))
Ver solución

Mediana ≈ 10 y cola ≈ 0,27. La logística tiene colas más pesadas que la normal: mismo centro, más extremos.

Ejercicio 3: triangular a mano y a código

Triangular(0,2,5): calculá Fc y predecí Q(0,2) y Q(0,8) con las ramas. Después comprobá generando 5000 y mirando la moda.

Ver una posible respuesta
import random
import math

random.seed(43)
a, c, b = 0.0, 2.0, 5.0
Fc = (c - a) / (b - a)

def Q(u):
    if u < Fc:
        return a + math.sqrt(u * (b - a) * (c - a))
    return b - math.sqrt((1 - u) * (b - a) * (b - c))

print("Fc =", Fc, " Q(0.2) =", round(Q(0.2), 3), " Q(0.8) =", round(Q(0.8), 3))
m = [Q(random.random()) for _ in range(5000)]
print("media muestral:", round(sum(m) / len(m), 3), "teórica:", round((a + b + c) / 3, 3))

Fc = 0,4. Q(0,2) ≈ 1,414 (rama izq.), Q(0,8) ≈ 3,114 (rama der.). Media teórica (a+b+c)/3 ≈ 2,333.

09 · Síntesis

Ideas para recordar

  • Analítica = despejar x de u = F(x): exacta y O(1) por muestra.
  • Memorizá Exp, Weibull, Pareto, logística y triangular por tramos.
  • Verificá con Q(0,5), Q(F(x₀)) y bordes antes de simular en serio.
  • Cuidá U vs 1−U en colas y clamp de u en logística/Cauchy.
  • Sin cerrada no se improvisa: va numérica o método dedicado.

En el próximo tema veremos qué hacer cuando no hay despeje posible: la inversión numérica.