01 · Punto de partida
Mezclar sin favoritismos
¿El orden de las preguntas de un examen? ¿El mazo antes de repartir? ¿La fila de atención al azar? Mezclar es elegir una de las n! permutaciones con igual probabilidad: si alguna ordenación sale más que otras, el sorteo está sesgado aunque cada carta “parezca” moverse.
Es el caso m = n del Tema 31 llevado al orden completo: el motor es Fisher-Yates (Tema 33) y la auditoría mira posiciones y puntos fijos, no solo “si se movió”.
- ¿Qué significa P(π) = 1/n! y cómo se testea con n = 52?
- ¿Por qué cada elemento cae en cada posición con prob. 1/n?
- ¿Cuántos puntos fijos esperar y con qué ley?
- ¿Qué mezclas populares no son uniformes?
02 · Definición
Uniformidad global y marginales planas
P(π) = 1/n! para toda π. Por simetría, P(elemento i en posición j) = 1/n y P(i antes que k) = 1/2. Los puntos fijos (i queda en i) suman media 1 con ley C(n,k)·D(n−k)/n!, donde D cuenta desarreglos.
Total equiprobable
La definición vive sobre las n! ordenaciones, no sobre cartas sueltas. Con n = 52 ni B = 10⁶ las recorre: se audita por marginales.
Posición plana
Cada elemento visita cada posición con 1/n. La matriz n×n de frecuencias debe ser plana: el test barato de justicia.
Fijos Poisson(1)
Con n ≥ 5, los puntos fijos siguen ≈ Poisson(1): P(0) ≈ 0,368 y media 1. Firma fina que el ingenuo no reproduce.
| n | P(0 fijos) | Media fijos | Lectura |
|---|---|---|---|
| 3 | 0,333 | 1,00 | Todavía lejos de 1/e |
| 6 | 0,368 | 1,00 | Ya clava Poisson(1) |
| 52 | ≈ 0,368 | 1,00 | El mazo: ~1 carta queda en su lugar |
03 · Anatomía
Fisher-Yates, sort y Sattolo
- Fisher-Yates O(n) exacto
- Recorrer i de n−1 a 1 sorteando j ∈ {0,…,i} e intercambiando. Cada permutación sale con 1/n!: el método de referencia (Tema 33).
- Sort por clave aleatoria
- Asignar U a cada elemento y ordenar: uniforme pero O(n log n) y con empates que hay que romper. Útil si ya hay un sort a mano, nunca la vía rápida.
- Sattolo: un solo ciclo
- Variante con j ∈ {0,…,i−1} que genera solo ciclos largos: ningún punto fijo jamás. Sirve para “amigo invisible”, no como mezcla justa.
- Ingenuo con rango fijo
- Sortear j ∈ {0,…,n−1} en cada paso repite salidas y sesga (algunas π salen más). Es el bug más famoso del muestreo.
Fisher-Yates
Uniforme en O(n)
n−1 sorteos, n! salidas equiprobables. Pasa marginales y puntos fijos con N grande.
Atajos sesgados
Parecen mezclar
Rango fijo o un solo pase dejan matriz de posiciones con manchas: algunas casillas sistemáticamente altas.
04 · Dónde se mezcla
Del mazo al experimento
- 1Juegos y sorteos.
Mazos, bolilleros, turnos: justicia = uniformidad sobre n!.
- 2Diseño experimental.
Orden de tratamientos y preguntas para anular efectos de posición y aprendizaje.
- 3Tests por permutación.
Reasignar etiquetas al azar miles de veces: la nula se construye mezclando.
- 4Puente a Fisher-Yates.
El algoritmo que lo hace perfecto en O(n), paso a paso. (Tema 33)
05 · Representación en Python
Mezcla y matriz de posiciones
Fisher-Yates a mano más la matriz n×n de frecuencias: cada casilla debe rondar 1/n.
Python en tu navegador. Subí n a 10: cada casilla debe rondar 0,10.
import random
random.seed(280)
n, B = 6, 6000
def fisher_yates(xs):
xs = list(xs)
for i in range(len(xs) - 1, 0, -1):
j = int((i + 1) * random.random())
xs[i], xs[j] = xs[j], xs[i]
return xs
mat = [[0]*n for _ in range(n)]
fijos = 0
for _ in range(B):
p = fisher_yates(range(n))
fijos += sum(1 for i, v in enumerate(p) if i == v) / B
for j, v in enumerate(p):
mat[v][j] += 1
print("casilla (0,0):", round(mat[0][0]/B, 3), "vs", round(1/n, 3))
print("fijos medios:", round(fijos, 3), "vs 1.0")
Casillas ≈ 0,167 y fijos ≈ 1,0. Si una diagonal queda alta, el rango del sorteo está mal.
06 · Exploración
Laboratorio: fijos que tienden a Poisson(1)
Movete n y B. Las barras cuentan puntos fijos 0…n en B mezclas; los rombos son C(n,k)·D(n−k)/n!. Desde n = 5 la forma ya es Poisson(1) con P(0) ≈ 0,368.
Puntos fijos de la mezcla
Fijos = #{i : π(i) = i} ≈ Poisson(1)
Con n 6 y B 6000, fijos ≈ 1 y P(0) ≈ 0,368.
Barras 0…n vs rombos exactos. Probá n = 3 (todavía no Poisson) y n = 10 (clavado).
Preguntas para explorar
- Con n = 6, ¿fijos medios y P(0) teóricos?
- Bajá a n = 3. ¿P(0) = 0,333 se despega de 1/e?
- Subí a n = 10 con B = 500. ¿Las barras altas (k ≥ 4) quedan vacías por sesgo o por rareza?
Ver respuestas sugeridas
- Media 1 y P(0) = 0,368 (265/720).
- Sí: 2/6 = 0,333. El límite 1/e necesita n ≥ 5 para apreciarse.
- Rareza: P(4 fijos) ≈ 0,004 con n = 10; con B = 500 se esperan ~2 casos. Vacío ocasional es normal.
07 · Comprensión
Confusiones frecuentes
«Un pase de intercambios ya mezcla»
Intercambiar cada i con un j fijo o aleatorio sin rango menguante no alcanza n! salidas equiprobables. Fisher-Yates exige j ∈ {0,…,i}.
«Sort con clave aleatoria es exacto»
Es uniforme si las claves son continuas iid, pero paga O(n log n) y los empates discretos la rompen. Exacto ≠ eficiente.
«Sattolo sirve como mezcla»
Sattolo prohíbe puntos fijos por diseño: P(0 fijos) = 1 en vez de 0,368. Es otro sorteo, para otro problema.
«Con B = n! valido todo»
Con n = 10, n! ≈ 3,6 millones: validar por marginales 1/n y fijos Poisson(1), no por enumeración.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: matriz plana n = 5
n = 5, B = 10000 (semilla 281): cada casilla debe rondar 0,20 con error máx. < 0,02.
import random
random.seed(281)
n, B = 5, 10000
mat = [[0]*n for _ in range(n)]
for _ in range(B):
xs = list(range(n))
for i in range(n-1, 0, -1):
j = int((i+1)*random.random())
xs[i], xs[j] = xs[j], xs[i]
for j, v in enumerate(xs):
mat[v][j] += 1
f = [c/B for fila in mat for c in fila]
print(round(min(f), 3), round(max(f), 3), "vs 0.2")
Ver solución razonada
Banda ≈ 0,19–0,21. Manchas persistentes con B = 10000 delatan rango mal puesto.
Ejercicio 2: desarreglo del mazo chico
n = 6, B = 8000: estimá P(0 fijos) ≈ 0,368 y compará con 1/e.
import random
import math
random.seed(282)
n, B = 6, 8000
cero = 0
for _ in range(B):
xs = list(range(n))
for i in range(n-1, 0, -1):
j = int((i+1)*random.random())
xs[i], xs[j] = xs[j], xs[i]
if all(i != v for i, v in enumerate(xs)):
cero += 1
print(round(cero/B, 3), "vs", round(1/math.e, 3))
Ver solución
≈ 0,368 (típicamente 0,355–0,38). Con Sattolo daría 1,0: otro sorteo.
Ejercicio 3: cazar el rango fijo
Compará Fisher-Yates (j ≤ i) contra ingenuo (j en todo n) con n = 4 y B = 20000: mirá la casilla (0,0).
Ver una posible respuesta
import random
random.seed(283)
n, B = 4, 20000
for nombre, bien in [("FY", True), ("ingenuo", False)]:
c00 = 0
for _ in range(B):
xs = list(range(n))
for i in range(n-1, 0, -1):
j = int((i+1)*random.random()) if bien else int(n*random.random())
xs[i], xs[j] = xs[j], xs[i]
c00 += (xs[0] == 0)
print(nombre, round(c00/B, 3), "vs 0.25")
FY clava 0,25; el ingenuo deja (0,0) en ≈ 0,42 con manchas peores adentro. La matriz lo delata.
09 · Síntesis
Ideas para recordar
- Justa = n! equiprobables; marginal 1/n por casilla.
- Fijos con media 1 y P(0) → 1/e: firma fina.
- Fisher-Yates O(n) exacto; sort O(n log n) caro.
- Sattolo e ingenuo no son mezclas justas.
- Auditar con matriz de posiciones, no con “se movió”.
En el próximo tema el algoritmo estrella: Fisher-Yates paso a paso.