01 · Punto de partida
El error que no se diluye
El ruido se achica con N (Tema 1); el sesgo, no: es una desviación sistemática del valor esperado que persiste con N = 12 millones. Si tu dado da al 6 con prob. 0,18 en vez de 0,1667, ninguna réplica más lo arregla: hay que encontrar la causa en la cadena semilla → entero → mapeo → rango.
Este tema cosecha lo sembrado en los Temas 19–23 y 33: los 5 sesgos clásicos con su firma (cómo se ve) y su cura (cómo se arregla).
- ¿Cómo distingo sesgo de mala suerte?
- ¿Cuáles son las 5 causas y en qué eslabón viven?
- ¿Qué firma deja cada uno en barras y χ²?
- ¿Por qué el sesgo no se compensa con más N?
02 · Definición
Ruido frente a sesgo
Ruido
Desvío aleatorio ±1/√N que se achica: con N ×4 cae a la mitad. Frecuencia 0,17 con N = 60 es ruido.
Sesgo
Desvío fijo δ que no se mueve: 0,17 con N = 12000 frente a 0,1667 ± 0,003 es sesgo de resto 4 (Tema 22).
Cadena
Todo sesgo nace en un eslabón: fuente, divisor, redondeo, rango o selección. La firma dice cuál.
| Causa | Firma | Cura |
|---|---|---|
% k con resto r | r caras altas en 1+r/q | Rechazo (Tema 22) |
Dividir por m−1 | El 1/b aparece; int(u·k) carga el tope | Dividir por m (Temas 19–20) |
round en discretos | Bordes a la mitad | floor (Tema 22) |
| Off-by-one en rango | Un valor falta o sobra | k = high−low+1 (Temas 22–23) |
/ RAND_MAX en C | El 1 sale 1/(R+1) | / (RAND_MAX+1.0) (Tema 20) |
03 · Firmas y diagnóstico
Leer las barras como un médico
Cada causa deja huella distinta en el histograma de k caras: el % eleva las primeras r; el round hunde los bordes; el off-by-one vacía o duplica un extremo; el /(m−1) crea un átomo en el tope.
- Protocolo N×4
- Medir el desvío con N y con 4N: si cae a la mitad, ruido (seguir); si queda, sesgo (diagnosticar por firma y corregir la causa, no los datos).
- No maquillar
- Reponderar a posteriori (“le resto 0,01 al 6”) esconde el χ² y rompe independencia: se corrige el código, no la salida.
- Sesgo heredado
- Un mapeo viciado contamina sorteos (Tema 23), muestras (Tema 25) y simulaciones enteras (Tema 44): el eslabón más barato de arreglar es el primero.
Bien diagnosticado
Firma → causa → cura
Barras dicen “primeras altas” → resto → rechazo. Un cambio, χ² en verde, informe con antes/después.
Mal diagnosticado
Culpar al generador
Cambiar MT por PCG cuando el bug era un round: el sesgo sobrevive al cambio y se pierde una semana.
04 · Ejemplos
Tres historiales clínicos
- 1
% 6con m = 100.Cuatro caras en 0,17, dos en 0,16, χ² ≈ 25: resto 4 → rechazo.
- 2
round(u·6)+1.1 y 6 en ≈ 0,083, resto en ≈ 0,167: bordes a la mitad → floor.
- 3
randint(0, len).IndexError1/7 de las veces + el último “sale menos”: off-by-one →randrange/choice.
05 · Implementación en Python
Medir tres sesgos de una vez
Comparamos sano (floor), % con resto y round sobre el mismo N = 12000: el χ² y las firmas hablan solas.
Python en tu navegador. Bajá N a 600 y mirá cómo el % se esconde en el ruido: el protocolo N×4 lo desenmascara.
import math
import random
def chi6(obs):
e = sum(obs) / 6
return round(sum((o - e) ** 2 / e for o in obs), 2)
rng = random.Random(34)
N = 12000
us = [rng.random() for _ in range(N)]
floor = [1 + math.floor(u * 6) for u in us]
redon = [1 + round(u * 6) for u in us]
xs = [rng.randrange(100) for _ in range(N)]
mod = [(x % 6) + 1 for x in xs]
for nombre, dados in [("floor", floor), ("round", redon), ("mod100", mod)]:
obs = [dados.count(c) for c in range(1, 7)]
print(nombre, [round(o / N, 4) for o in obs], "chi2:", chi6(obs))
floor ≈ 0,1667 (χ² ≈ 5, pasa); round hunde bordes; mod eleva 4 caras (χ² ≈ 40+, rechaza).
Protocolo N×4
import random
rng = random.Random(34)
for n in [3000, 12000]:
xs = [rng.randrange(100) for _ in range(n)]
dados = [(x % 6) + 1 for x in xs]
f1 = dados.count(1) / n
print(n, round(f1, 4), "desvio:", round(f1 - 1 / 6, 4))
06 · Exploración
Laboratorio: galería de sesgos
Cuatro dados con N = 12000: sano, % con resto, round y un atajo con /(m−1) que carga el 6. Las barras naranjas exceden la banda E ± 2√E; el panel trae χ² (crítico 11,07).
Firmas a la vista
el sesgo no se diluye
Sano con N = 12000: seis caras en banda.
Cada sesgo tiene su firma: primeras altas (%), bordes hundidos (round), tope disparado (m−1).
Preguntas para explorar
- Con
%y N = 1500: ¿χ² rechaza siempre? ¿Y con N = 12000? - Con
round: ¿qué caras se hunden y a cuánto? ¿Por qué justo esas? - Si duplicás N en el sano, ¿el desvío máximo se achica? ¿Y en los sesgados?
Ver respuestas sugeridas
- Con N = 1500 a veces “pasa” (potencia justa); con N = 12000 rechaza sistemático: el sesgo emerge del ruido.
- 1 y 6 a ≈ 0,083 (la mitad):
roundles da medio intervalo ([0,1/12) y (11/12,1)) frente a 1/6 entero. - En el sano sí (÷√2 por duplicación); en sesgados no: el δ fijo queda clavado.
07 · Comprensión
Confusiones frecuentes
«0,17 con N = 600 ya es sesgo»
La banda con N = 600 es ±0,012: 0,17 entra en ruido. Sesgo se declara con N grande y réplica, no con un conteo chico.
«Compenso restándole al 6»
Maquillaje: el χ² baja pero la independencia y los pares siguen rotos. Se arregla el código, no la planilla.
«Si cambio de generador se va»
Solo si la causa era la fuente (RANDU, período). Si era el mapeo (%, round), el sesgo viaja con vos al generador nuevo.
«Sesgo chico no importa»
En colas y sorteos millonarios, 1 pp de sesgo son miles de casos y plata: lo “chico” escala con N aunque el δ no se mueva.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: N×4 decide
El 1 sale 0,172 con N = 3000. ¿Ruido o sesgo? Repetilo con N = 12000 del mismo % y compará desvíos.
import random
rng = random.Random(2)
for n in [3000, 12000]:
xs = [rng.randrange(100) for _ in range(n)]
f1 = sum(1 for x in xs if x % 6 == 0) / n
print(n, round(f1, 4))
Ver solución razonada
Da ≈ 0,171 con N = 3000 y ≈ 0,170 con N = 12000: el desvío (+0,004) no se achica al cuadruplicar N → sesgo (resto 4 da 17/100 = 0,17 exacto). Ruido habría caído a la mitad (≈ +0,002).
Ejercicio 2: bordes del round
Demostrá que round(u·6)+1 da al 1 prob. 1/12 con N = 12000.
import random
rng = random.Random(2)
N = 12000
dados = [1 + round(rng.random() * 6) for _ in range(N)]
print(round(dados.count(1) / N, 4), round(dados.count(3) / N, 4))
Ver solución
1 ≈ 0,083 (1/12) y 3 ≈ 0,167 (1/6): bordes a la mitad por construcción de intervalos de redondeo.
Ejercicio 3: el átomo del tope
Mostrá que dividir por m−1 con m = 16 crea un 1,0 con prob. 1/16 que luego carga el 6.
Ver una posible respuesta
import math
xs = list(range(16))
us = [x / 15 for x in xs]
dados = [min(6, 1 + math.floor(u * 6)) for u in us]
print("unos:", sum(1 for u in us if u == 1.0))
print("frec 6:", round(dados.count(6) / 16, 4))
Un 1,0 (1/16) que floor(u·6)+1 mandaría a 7, recortado a 6: el 6 queda en 2/16 = 0,125 en vez de 1/6… con m grande el átomo es 1/m pero sistemático.
09 · Síntesis
Ideas para recordar
- Sesgo = δ fijo; ruido ∝ 1/√N. N×4 los separa.
- 5 causas: % con resto, /(m−1), round, off-by-one, /RAND_MAX.
- Cada una deja firma en barras: leer antes de culpar al generador.
- Se corrige el código (rechazo, floor, k, divisor), nunca la salida.
- Sesgo chico × N grande = daño grande.
En el próximo tema, los errores de todos los días: trampas al generar enteros (módulo, redondeo y bordes).