Números Pseudoaleatorios · Tema 29

Pruebas de frecuencia

Contar apariciones por intervalos: el chi-cuadrado del Tema 27 aplicado caja por caja, con desvío máximo visible.

01 · Punto de partida

El chi-cuadrado puesto a contar

El Tema 27 te dio la teoría (χ², grados, críticos) y el Tema 28 te recordó que el orden importa. La prueba de frecuencia es el χ² con overol: partís [0,1) en k = 10 décimos, contás, y mirás caja por caja cuál se sale de la banda E ± 2√E. Es el test que corre primero en cualquier batería: barato, visual y demoledor contra dados cargados y % viciados.

La diferencia con el Tema 27 es de foco: allá decidía un número; acá el informe muestra dónde falla (cajas 1–4 altas, 5–6 bajas) para diagnosticar la causa.

  • ¿Por qué k = 10 es el estándar de frecuencia?
  • ¿Cuánto puede desviarse una caja sana?
  • ¿Cómo leo “qué cajas fallan” además del veredicto?
  • ¿Frecuencia que pasa + rachas que fallan = qué?

02 · Definición

Cajas, banda y χ²

◈

Cajas décimos

k = 10 intervalos [0,0,1), …, [0,9,1): convención histórica, E redondo y gráfico legible de un vistazo.

⇄

Banda 2√E

Cada caja es Binomial(N, 1/10) ≈ Normal(E, √E): sana si cae en E ± 2√E (~95 %). Fuera = candidata a sesgo.

▣

χ² con 9 gl

La suma decide: χ² < 16,92 pasa al 5 %. Una caja fuera no condena; χ² alto con patrón sí.

Lectura caja por caja (N = 1000, E = 100).
SituaciónSeñalLectura
Todas en 100 ± 20χ² ≈ 9Pasa: ruido honesto
Una en 150, resto en ~94χ² ≈ 28Rechaza: pico localizado (dígito cargado)
Mitad alta, mitad bajaχ² ≈ 40Rechaza: pendiente o escalón (mapeo roto)

03 · Procedimiento correcto

N, E y patrón

Con N = 1000 y k = 10, E = 100 y la banda es 100 ± 20: contar es decidir a ojo antes del χ². Con N = 100 (E = 10, banda 10 ± 6) todo “pasa” por falta de potencia: la frecuencia exige N ≥ 1000 para k = 10.

N ≥ 100·k
Regla práctica: E ≥ 100 para que la banda ±2√E (±20 %) tenga filo. Con E = 10 la banda es ±63 %: inútil.
Patrón sobre número
Cuatro cajas altas seguidas = resto de módulo (Tema 22); una sola alta = cara cargada; sierra = resolución gruesa (Tema 19).
Frecuencia + orden
Frecuencia que pasa y rachas que fallan = alternada del Tema 28: marginal bien, orden mal. El informe cruza ambos.

Bien contada

k = 10, N ≥ 1000

Barras en banda, χ² ≈ 9, informe con tabla O/E por caja y gráfico. Diagnóstico localizado si falla.

Mal contada

N = 100, k = 10

E = 10 con banda ±6: hasta un dado cargado 2× “pasa”. Potencia nula disfrazada de veredicto.

04 · Ejemplos

Tres conteos típicos

Partir en 10→Contar O→Banda + χ²
  1. 1
    Sano, N = 5000.

    E = 500, banda 500 ± 45: todas dentro, χ² ≈ 9 < 16,92. Pasa.

  2. 2
    Dado % con resto, N = 6000.

    Cuatro caras en ~1020, dos en ~960: χ² ≈ 25. El patrón “4 altas” firma el resto 4 del Tema 22.

  3. 3
    Dígito 7 cargado ×2.

    Caja 8 (0,7–0,8) en ~2E, resto en ~0,9E: χ² ≈ 60. Pico único, causa única.

05 · Implementación en Python

Tabla O/E con veredicto

Función que devuelve conteos, χ² y veredicto al 5 % con k = 10. Probala con random y con un “7 cargado” simulado.

Python en tu navegador. Bajá N a 100 y mirá cómo hasta el cargado “pasa”: la potencia vive en N.

import math
import random

def prueba_frecuencia(us, k=10, critico=16.92):
    n = len(us)
    e = n / k
    obs = [0] * k
    for u in us:
        obs[min(k - 1, int(u * k))] += 1
    chi = sum((o - e) ** 2 / e for o in obs)
    banda = 2 * math.sqrt(e)
    fuera = [i for i, o in enumerate(obs) if abs(o - e) > banda]
    return obs, round(chi, 2), chi < critico, fuera


rng = random.Random(29)
us = [rng.random() for _ in range(5000)]
obs, chi, pasa, fuera = prueba_frecuencia(us)
print("obs:", obs)
print("chi2:", chi, "pasa:", pasa, "fuera de banda:", fuera)

Diez cajas ≈ 500 ± 45, χ² de un dígito: pasa sin cajas fuera.

El 7 cargado

import math
import random

def prueba_frecuencia(us, k=10, critico=16.92):
    e = len(us) / k
    obs = [0] * k
    for u in us:
        obs[min(k - 1, int(u * k))] += 1
    chi = sum((o - e) ** 2 / e for o in obs)
    return obs, round(chi, 2), chi < critico


rng = random.Random(29)
us = []
for _ in range(5000):
    u = rng.random()
    us.append(0.75 if rng.random() < 0.1 else u)  # 10 % extra al decimo 8
obs, chi, pasa = prueba_frecuencia(us)
print("obs:", obs)
print("chi2:", chi, "pasa:", pasa)

06 · Exploración

Laboratorio: la banda manda

Diez décimos con banda E ± 2√E sombreada. Fuentes: sano, % con resto y 7 cargado. Subí N: el sano se mete en banda, los viciados se escapan más.

EXPERIMENTO 29

Décimos bajo lupa

E = N/10 · banda ±2√E

Los resultados numéricos aparecen debajo.
χ² (crit 16,92)—
Cajas fuera—
Máx desvío—
Veredicto—

Sano con N = 5000: diez cajas en banda.

Barras naranjas fuera de la banda sombreada: candidatas a sesgo. El χ² decide si el conjunto condena.

Preguntas para explorar

  1. Con sano y N = 500: ¿alguna caja sale de banda? ¿χ² pasa igual?
  2. Con 7 cargado y N = 10000: ¿qué caja se dispara y cuánto sobre E?
  3. Con sesgo % y N grande: ¿el patrón es un pico o varias altas? ¿Qué firma deja el resto?
Ver respuestas sugeridas
  1. Puede salir 1 por azar (10 cajas al 95 %): χ² ≈ 9 igual pasa. Una fuera ≠ condena.
  2. La caja 8 (0,7–0,8) ≈ 2E: pico único, χ² ≈ 100+. Causa única, diagnóstico directo.
  3. Varias altas seguidas (las del resto): firma del % del Tema 22, no de cara cargada.

07 · Comprensión

Confusiones frecuentes

«Una caja fuera = generador roto»

Con 10 cajas al 95 % lo esperado es 0,5 fuera por azar. Condena χ² alto + patrón, no una escapada sola.

«N = 100 alcanza para k = 10»

E = 10 con banda ±6: hasta un cargado ×2 se esconde. Frecuencia seria exige N ≥ 1000 (E ≥ 100).

«Frecuencia que pasa = independencia»

La alternada 0,1/0,9 pasa décimos y es zigzag puro: falta el Tema 28 (rachas/corr) y el 30 (pares).

«Más cajas siempre es más fino»

Solo con N que acompañe (E ≥ 5 mínimo, ≥ 100 ideal). k = 50 con N = 500 da E = 10: ruido que finge precisión.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: décimos sanos

Contá 5000 de random en 10 décimos y verificá χ² < 16,92 con ninguna o una caja fuera.

import math
import random

rng = random.Random(13)
us = [rng.random() for _ in range(5000)]
obs = [0] * 10
for u in us:
    obs[min(9, int(u * 10))] += 1
e = 500
chi = sum((o - e) ** 2 / e for o in obs)
print(obs, round(chi, 2))
print("fuera:", [i for i, o in enumerate(obs) if abs(o - e) > 2 * math.sqrt(e)])
Ver solución razonada

χ² ≈ 5–14 con 0–1 fuera: pasa. Si salen 2 fuera pero χ² ≈ 10, sigue pasando: las bandas son guía, el χ² decide.

Ejercicio 2: el % con resto en décimos

Proyectá fuente randrange(100) a 10 décimos vía % 10… y notá qué pasa cuando k divide a m. Luego con k = 6.

import random

rng = random.Random(13)
xs = [rng.randrange(100) for _ in range(6000)]
d10 = [(x % 10) for x in xs]
d6 = [(x % 6) for x in xs]
print("k=10:", [d10.count(c) for c in range(10)])
print("k=6 :", [d6.count(c) for c in range(6)])
Ver solución

k = 10 parejo (100 % 10 = 0, sin resto); k = 6 viciado (resto 4: cuatro caras en ~1020). El mismo % absuelve o condena según k.

Ejercicio 3: N que esconde

Mostrá que el 7 cargado ×2 “pasa” con N = 100 pero cae con N = 5000.

Ver una posible respuesta
import random

def chi10(us):
    e = len(us) / 10
    obs = [0] * 10
    for u in us:
        obs[min(9, int(u * 10))] += 1
    return sum((o - e) ** 2 / e for o in obs)


rng = random.Random(13)
for n in [100, 5000]:
    us = [0.75 if rng.random() < 0.1 else rng.random() for _ in range(n)]
    print(n, round(chi10(us), 2))

N = 100: χ² ≈ 8–14 (pasa por falta de potencia); N = 5000: χ² ≈ 60+ (condena). La potencia vive en N.

09 · Síntesis

Ideas para recordar

  • Frecuencia k = 10: E = N/10, banda E ± 2√E, χ² < 16,92 al 5 %.
  • El gráfico localiza (pico, pendiente, sierra); el χ² condena.
  • N ≥ 1000 para k = 10: sin N no hay filo.
  • Una caja fuera ≠ condena; patrón + χ² alto = diagnóstico.
  • Frecuencia no ve orden: cruzar con rachas/corr (Tema 28).

En el próximo tema subimos de dimensión: pruebas de series con pares y ternas.