Generación de Variables Aleatorias · Tema 31

Muestreo sin reemplazo

Subconjuntos equiprobables sin repetir: Fisher-Yates parcial, Floyd y conteos hipergeométricos.

01 · Punto de partida

Elegir m distintos de n

¿5 ganadores entre 20 inscriptos? ¿4 piezas a auditar de un lote de 50? ¿El 30 % de test sin filtrar nada al train? Cada elemento puede salir a lo sumo una vez: el resultado es un subconjunto de tamaño m, equiprobable entre los C(n,m).

Es el espejo del Tema 30: allí repetir era la información; aquí repetir es el bug. El motor pasa de índices iid a permutación parcial.

  • ¿Por qué sortear índices iid y descartar repetidos sesga si se hace mal?
  • ¿Qué probabilidad tiene cada elemento de salir?
  • ¿Fisher-Yates parcial, Floyd o sample según n y m?
  • ¿Cómo se audita con la hipergeométrica?

02 · Definición

Uniformidad sobre subconjuntos

P(S) = 1/C(n,m) para todo S de tamaño m. P(i ∈ S) = m/n por simetría. Si la población tiene K marcados, los marcados en la muestra son Hipergeométrica(n,K,m): media m·K/n.

≠

Distintos garantizados

El algoritmo debe impedir el repetido por construcción (permutar, no reintentar): el rechazo ingenuo cambia el costo y, mal cortado, la ley.

H(n,K,m)

Conteos hipergeométricos

Sin reemplazo los ensayos no son independientes: la varianza lleva el factor (n−m)/(n−1). Con m = n todo sale siempre.

m≪n

Parcial vs total

Si m ≪ n, permutar todo desperdicia O(n): basta mezclar las primeras m posiciones o construir el conjunto directo.

Con n = 20 y m = 5: lo que promete el diseño.
HechoValorLectura
P(7 sale)5/20 = 0,25Cada elemento, 1 de cada 4 muestras
SubconjuntosC(20,5) = 15 504Todos equiprobables
Defectuosas (K=4)media 1,0m·K/n = 5·4/20

03 · Anatomía

Parcial, Floyd y descarte

Fisher-Yates parcial O(m)
Mezclar solo las primeras m posiciones: en el paso i sortear j ∈ {i,…,n−1} e intercambiar. Toma los primeros m: subconjunto uniforme sin tocar el resto.
Floyd O(m) ordenado
Construir el conjunto de atrás hacia adelante con inclusiones calibradas. Ideal con n enorme y m chico; devuelve ordenado, no en orden aleatorio.
Rechazo con conjunto
Sortear int(n·U) y guardar si es nuevo hasta juntar m. Simple con m ≪ n; con m ≈ n las colisiones lo vuelven O(n log n) o peor.
Mezcla total + corte O(n)
Permutar todo (Tema 33) y quedarse con los primeros m. La vía simple si n es chico o si además se necesita el orden aleatorio completo.

Parcial / Floyd

Eficientes con m ≪ n

Trabajo proporcional a la muestra, no a la población. La opción cuando n es catálogo y m es puñado.

Reintento sin control

Lento y frágil

Con m ≈ n casi todo sorteo colisiona; y si se “completa” con los que faltan, el subconjunto deja de ser uniforme.

04 · Dónde no se repite

Del sorteo al reparto

población n→m distintos→muestra justa
  1. 1
    Sorteos y loterías.

    Ganadores, jurados, auditorías: nadie sale dos veces.

  2. 2
    Train / test.

    Partir datos sin fuga: cada fila va a entrenar o a test, nunca a ambos.

  3. 3
    Control de calidad.

    Piezas a inspeccionar de un lote: conteos hipergeométricos con K defectuosas.

  4. 4
    Puente a permutaciones.

    El m = n es la permutación completa del Tema 32; Fisher-Yates total es el caso límite.

05 · Representación en Python

Parcial a mano contra sample

Misma población, mismo m: Fisher-Yates parcial manual frente a random.sample. Ambas deben dar inclusión ≈ m/n por elemento.

Python en tu navegador. Subí m a 15: la inclusión debe ir a 0,75.

import random

random.seed(270)
n, m, B = 20, 5, 4000

def subconjunto(m, n):
    idx = list(range(n))
    for i in range(m):
        j = i + int((n - i) * random.random())
        idx[i], idx[j] = idx[j], idx[i]
    return sorted(idx[:m])

frec = [0] * n
for _ in range(B):
    for i in subconjunto(m, n):
        frec[i] += 1
print("parcial:", [round(f/B, 3) for f in frec[:5]], "vs", m/n)
random.seed(270)
frec2 = [0] * n
for _ in range(B):
    for i in sorted(random.sample(range(n), m)):
        frec2[i] += 1
print("sample: ", [round(f/B, 3) for f in frec2[:5]], "vs", m/n)

Inclusión ≈ 0,25 en ambas. Si algún índice da ≈ 0, el rango del sorteo parcial está mal.

06 · Exploración

Laboratorio: planicie de inclusión

Movete m y B con n = 20 fijo. Las barras son la frecuencia de inclusión de cada elemento 0…19; la línea es m/n. Con B grande, planicie; con B chica, ruido.

EXPERIMENTO 31

Subconjunto de m en 20

P(i ∈ S) = m/n

Los resultados numéricos aparecen debajo.
Inclusión media0,250
Teórica m/n0,250
Error máx.0,000
Chi-cuadrado0,00

Con m 5 y B 2000, planicie en 0,25.

20 barras vs línea teórica. Probá m = 15 (línea 0,75) y B = 200 (ruido).

Preguntas para explorar

  1. Con m = 5, ¿inclusión teórica? ¿Chi-cuadrado chico?
  2. Subí m a 19. ¿Todas las barras van a ≈ 0,95? ¿Por qué?
  3. Bajá B a 200. ¿El error máx. crece? ¿Sesgo o ruido?
Ver respuestas sugeridas
  1. 0,25 y chi ≈ grados de libertad (19): el ruido esperado, no sesgo.
  2. Sí: cada muestra deja afuera solo 1 de 20, así que casi todos entran casi siempre.
  3. Ruido: el error típico por barra es √[p(1−p)/B] ≈ 0,01 con B = 2000 y ≈ 0,03 con B = 200.

07 · Comprensión

Confusiones frecuentes

«Sorteo m índices iid y listo»

Con reemplazo salen repetidos: ya no es subconjunto de tamaño m sino multiconjunto. Sin reemplazo exige construcción sin repetir.

«El rango del paso i da igual»

Debe ser {i,…,n−1}. Sortear en {0,…,n−1} en cada paso es el “Fisher-Yates ingenuo” sesgado del Tema 33.

«Ordeno el resultado y se arruina»

Ordenar el subconjunto no cambia la ley del conjunto; solo pierde el orden aleatorio (que Floyd ni siquiera produce).

«Con B = 100 ya valido»

La inclusión p = 0,25 con B = 100 tiene error típico ≈ 0,043 por barra: el chi baila. Validar con miles.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: lote con defectuosas

Lote n = 20 con K = 4 defectuosas, m = 5, B = 6000 (semilla 271): la media de defectuosas debe dar ≈ 1,0.

import random

random.seed(271)
n, K, m, B = 20, 4, 5, 6000
malas = set(range(K))
tot = 0
for _ in range(B):
    s = random.sample(range(n), m)
    tot += sum(1 for i in s if i in malas)
print(round(tot/B, 3), "vs", m*K/n)
Ver solución razonada

≈ 1,0 (típicamente 0,95–1,05). Es la media hipergeométrica m·K/n sin reemplazo.

Ejercicio 2: P(0 defectuosas)

Mismo lote: estimá P(ninguna defectuosa) ≈ C(16,5)/C(20,5) ≈ 0,282.

import random
import math

random.seed(272)
n, K, m, B = 20, 4, 5, 6000
malas = set(range(K))
cero = sum(1 for _ in range(B)
           if not any(i in malas for i in random.sample(range(n), m)))
print(round(cero/B, 3), "vs", round(math.comb(16,5)/math.comb(20,5), 3))
Ver solución

≈ 0,28. Con reemplazo daría (0,8)⁵ ≈ 0,328: el sin reemplazo “ayuda” a encontrar defectuosas.

Ejercicio 3: split train/test 70/30

Con n = 100, separá 70/30 con semilla fija y verificá disjuntos, unión completa y tamaños exactos.

Ver una posible respuesta
import random

random.seed(273)
n, m = 100, 70
train = set(random.sample(range(n), m))
test = set(range(n)) - train
print(len(train), len(test), len(train & test), len(train | test))

70, 30, 0 y 100: partición exacta sin fuga. Con reemplazo habría repetidos y huecos.

09 · Síntesis

Ideas para recordar

  • Sin reemplazo: P(S) = 1/C(n,m), P(i ∈ S) = m/n.
  • Conteos de clase ⇒ hipergeométrica, no binomial.
  • Parcial O(m) o Floyd con m ≪ n; total + corte con n chico.
  • Rango {i,…,n−1} en cada paso: el ingenuo sesga.
  • Auditar inclusión por elemento + chi contra m/n.

En el próximo tema mezclamos todo: permutaciones aleatorias.