Números Pseudoaleatorios · Tema 28

Pruebas de independencia

Detectar dependencias ocultas: autocorrelación por lags y test de rachas, con bandas del 95 %.

01 · Punto de partida

Uniforme no es independiente

La secuencia 0,1 · 0,9 · 0,1 · 0,9 … pasa chi-cuadrado (Tema 27) con nota perfecta y es una calamidad: sabiendo un valor sabés el siguiente. La uniformidad mira cuántos caen en cada caja; la independencia mira en qué orden llegan. Sin la segunda pata, tu “azar” es un disco rayado con buena distribución.

Este tema trae las dos pruebas baratas que ningún auditor perdona: autocorrelación (¿el pasado lineal predice?) y rachas (¿sube y baja como debe?).

  • ¿Qué mide la correlación lag-h y cuánto vale en un sano?
  • ¿Qué es una racha y cuántas debe haber en N valores?
  • ¿Por qué mirar varios lags y no solo el 1?
  • ¿Corr ≈ 0 certifica independencia?

02 · Definición

Dos lentes para el orden

◈

Autocorrelación

corr(h) entre uₙ y uₙ₊ₕ: en un sano ≈ 0 con banda ±1,96/√N. El correlograma grafica h = 1…10.

⇄

Rachas

Racha = tramo monótono (+/− entre vecinos). En N valores sanos: media (2N−1)/3, var (16N−29)/90, Z normal.

▣

Lags varios

Un LCG malo esconde corr 0 en lag-1 y explota en lag-3; RANDU duerme en 1D y despierta en 3D. Mirar 1…10, no uno.

Qué delata cada prueba.
PruebaDetectaNo ve
AutocorrelaciónDependencia lineal por lagDependencia no lineal (uₙ₊₁ ≈ 4uₙ(1−uₙ))
Rachas sube/bajaAlternancia o pegoteo excesivoSesgo de media (pasa con media corrida)
Ambas + χ²Lo lineal y lo marginalEstructuras en pares/ternas (Temas 30, 32)

03 · Procedimiento correcto

Bandas, Z y réplicas

Con N = 2000 la banda del correlograma es ±1,96/√2000 ≈ ±0,044: barras dentro = ruido; barras que la cruzan sistemáticamente = dependencia. Para rachas, Z = (R − media)/√var se compara con ±1,96 al 5 %: |Z| > 1,96 rechaza.

N previo
Fijar N y lags (1…10) antes de mirar. Con N = 50 las bandas son ±0,28: todo “pasa” por falta de potencia, no por calidad.
Z en ambas colas
Pocas rachas (pegoteo, Z ≪ 0) y muchas rachas (zigzag, Z ≫ 0) rechazan: el test es a dos colas, no solo “pocas”.
Corr 0 ≠ independencia
Corr solo ve lo lineal: la parábola logística xₙ₊₁ = 4xₙ(1−xₙ) da corr ≈ 0 y es totalmente determinista. Para lo no lineal van series y gráficos (Temas 30–31).

Bien testeado

Correlograma + rachas

Lags 1…10 dentro de bandas, |Z| < 1,96, réplica con otra semilla. Informe con N, lags, corr(1) y Z.

Mal testeado

Solo lag-1

Un generador con período 3 da corr(1) ≈ −0,5 pero corr(3) ≈ 1: mirar un lag es cerrar un ojo.

04 · Ejemplos

Tres firmas típicas

Secuencia→corr + rachas→Veredicto
  1. 1
    Sano, N = 2000.

    corr(1…10) dentro de ±0,044, rachas ≈ 1333 con |Z| < 2: pasa.

  2. 2
    Alternada 0,1/0,9.

    corr(1) ≈ −1, rachas = N−1 = 1999 con Z ≈ +25: rechazo estrepitoso en ambas.

  3. 3
    Juguete m = 16.

    corr(1) positiva estable (~0,2) y rachas escasas: el ciclo corto se delata en el orden.

05 · Implementación en Python

corr + rachas a mano

Dos funciones puras, sin librerías: autocorrelación por lag y test de rachas sube/baja con Z. Probalas con random y con la alternada.

Python en tu navegador. Cambiá N a 200 y mirá cómo se ensanchan las bandas: la potencia vive en N.

import math
import random

def corr_lag(us, h=1):
    n = len(us)
    m = sum(us) / n
    var = sum((u - m) ** 2 for u in us) / n
    cov = sum((us[i] - m) * (us[i + h] - m) for i in range(n - h)) / (n - h)
    return cov / var if var else 0.0


def test_rachas(us):
    n = len(us)
    signos = [1 if us[i + 1] > us[i] else -1 for i in range(n - 1)]
    rachas = 1 + sum(1 for i in range(len(signos) - 1) if signos[i] != signos[i + 1])
    media = (2 * n - 1) / 3
    var = (16 * n - 29) / 90
    z = (rachas - media) / math.sqrt(var)
    return rachas, round(z, 2)


rng = random.Random(28)
us = [rng.random() for _ in range(2000)]
print("corr1:", round(corr_lag(us), 4), "banda:", round(1.96 / math.sqrt(2000), 4))
print("rachas:", test_rachas(us))

corr ≈ 0 dentro de ±0,044 y Z chico: pasa ambas. La alternada da corr −1 y Z ≈ +25.

La alternada se delata

import math

def corr_lag(us, h=1):
    n = len(us)
    m = sum(us) / n
    var = sum((u - m) ** 2 for u in us) / n
    cov = sum((us[i] - m) * (us[i + h] - m) for i in range(n - h)) / (n - h)
    return cov / var if var else 0.0


alt = [0.1, 0.9] * 1000
print("corr1:", round(corr_lag(alt), 4), "corr2:", round(corr_lag(alt, 2), 4))

06 · Exploración

Laboratorio: correlograma en vivo

Tres fuentes, lags 1…8 con bandas del 95 %. El panel trae corr(1), rachas con Z y veredicto. Subí N: el sano se mete en bandas, los enfermos no.

EXPERIMENTO 28

Barras dentro o fuera

bandas ±1,96/√N

Los resultados numéricos aparecen debajo.
corr(1)—
Rachas (Z)—
Lags fuera—
Veredicto—

Sano con N = 500: barras dentro de bandas.

Barras naranjas cruzan las bandas: dependencia. La alternada alterna −1/+1 por construcción.

Preguntas para explorar

  1. Con sano y N = 100: ¿alguna barra cruza? ¿Y con N = 2000?
  2. Con alternada: ¿qué vale corr(1) y corr(2)? ¿Qué Z de rachas sale?
  3. Con juguete y N = 2000: ¿las barras se meten en bandas o persisten fuera?
Ver respuestas sugeridas
  1. Con N = 100 las bandas son ±0,196: casi todo “pasa” por falta de potencia. Con N = 2000 (±0,044) el sano sigue dentro.
  2. corr(1) ≈ −1, corr(2) ≈ +1, Z ≈ +25: zigzag perfecto, rechazo total.
  3. Persisten: la dependencia es estructural del ciclo, no ruido que se diluye.

07 · Comprensión

Confusiones frecuentes

«corr ≈ 0, es independiente»

Solo descarta lo lineal: la parábola logística es determinista con corr ≈ 0. Independencia exige batería (series, gráficos).

«Con lag-1 alcanza»

Dependencias de período 3 o 5 duermen en lag-1 y despiertan en su lag. El correlograma es 1…10 o no es.

«Muchas rachas es bueno (más mezcla)»

No: demasiadas rachas (Z ≫ 0) es zigzag artificial; demasiadas pocas (Z ≪ 0), pegoteo. Lo sano es el medio, |Z| < 1,96.

«Un lag fuera condena»

Con 10 lags al 5 % lo esperado por azar es 0,5 cruces: uno aislado se confirma con otra semilla, no se condena.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: correlograma sano

Calculá corr(1…5) de random con N = 2000 y verificá que todas caen en ±0,044.

import math
import random

def corr_lag(us, h):
    n = len(us)
    m = sum(us) / n
    var = sum((u - m) ** 2 for u in us) / n
    cov = sum((us[i] - m) * (us[i + h] - m) for i in range(n - h)) / (n - h)
    return cov / var


rng = random.Random(9)
us = [rng.random() for _ in range(2000)]
print([round(corr_lag(us, h), 4) for h in range(1, 6)])
Ver solución razonada

Cinco valores ≈ ±0,03 dentro de bandas: pasa. Si uno roza 0,05 aislado, repetir con otra semilla antes de sospechar.

Ejercicio 2: rachas del pegoteo

La secuencia de 2000 valores con bloques de 100 iguales (100×0,2, 100×0,8…) debe dar poquísimas rachas. Calculá Z.

import math

us = [0.2] * 100 + [0.8] * 100
us = us * 10
signos = [1 if us[i + 1] > us[i] else (-1 if us[i + 1] < us[i] else 0) for i in range(len(us) - 1)]
rachas = 1 + sum(1 for i in range(len(signos) - 1) if signos[i] != signos[i + 1] and 0 not in (signos[i], signos[i + 1]))
n = len(us)
z = (rachas - (2 * n - 1) / 3) / math.sqrt((16 * n - 29) / 90)
print(rachas, round(z, 2))
Ver solución

Z ≈ −40: poquísimas rachas, pegoteo total. El test a dos colas lo rechaza por la cola izquierda.

Ejercicio 3: período 3 escondido

La secuencia 0,2/0,5/0,8 repetida tiene corr(1) moderado pero corr(3) ≈ 1. Mostralo.

Ver una posible respuesta
def corr_lag(us, h):
    n = len(us)
    m = sum(us) / n
    var = sum((u - m) ** 2 for u in us) / n
    cov = sum((us[i] - m) * (us[i + h] - m) for i in range(n - h)) / (n - h)
    return round(cov / var, 4)


us = [0.2, 0.5, 0.8] * 700
print("corr1:", corr_lag(us, 1), "corr3:", corr_lag(us, 3))

corr(1) ≈ −0,5 pero corr(3) ≈ 1,0: el lag-1 solo “ve” la mitad del truco. Moraleja del correlograma completo.

09 · Síntesis

Ideas para recordar

  • Uniformidad mira cajas; independencia mira orden: hacen falta ambas.
  • Correlograma 1…10 con bandas ±1,96/√N; un cruce aislado se confirma.
  • Rachas: media (2N−1)/3, Z a dos colas, |Z| < 1,96.
  • corr ≈ 0 no certifica: solo descarta lo lineal.
  • N manda: con N chico todo pasa por falta de potencia.

En el próximo tema contamos lo más simple: pruebas de frecuencia por intervalos.