Muestreo de Floyd: un algoritmo ingenioso

Fuentes: Floyd's Sampling Algorithm

El algoritmo de muestreo de Floyd es una técnica ingeniosa para generar un subconjunto aleatorio de tamaño k de un conjunto de números del 1 al n. A diferencia de otros algoritmos de muestreo como el muestreo de reservorio, la intuición detrás de Floyd's Sampling no es inmediatamente obvia, lo que lo hace particularmente fascinante. Su funcionamiento se basa en una lógica de ramificación que dificulta un análisis combinatorio directo.

¿Cómo funciona? El algoritmo comienza con un conjunto vacío y, en cada iteración, considera un nuevo elemento del rango de 1 a n. Si el elemento aleatorio seleccionado ya está en el conjunto, se agrega el elemento actual (i) al conjunto. De lo contrario, el elemento aleatorio se agrega al conjunto. Este proceso se repite hasta que el conjunto contenga k elementos. El código proporcionado en el artículo ilustra esto de manera concisa. Una implementación en Python sería algo así: def floyd(n, k): s = set(); for i in range(n - k + 1, n + 1): t = random.randint(1, i); if t in s: s.add(i) else: s.add(t); return s

Dos perspectivas para entenderlo: El autor presenta dos formas de comprender el algoritmo. La primera perspectiva se centra en la uniformidad de la distribución. Cada iteración transforma un subconjunto de tamaño k en otro de tamaño k+1, manteniendo la distribución uniforme. Esto se demuestra mostrando que cada posible subconjunto de tamaño k+1 tiene exactamente k+1 entradas que lo generan. La segunda perspectiva establece una conexión sorprendente con el algoritmo de Fisher-Yates para permutar un array aleatoriamente. Floyd's Sampling puede verse como la ejecución de los últimos k intercambios del algoritmo de Fisher-Yates. En esencia, el algoritmo simula la selección de los últimos k elementos de un array aleatoriamente permutado.

Casos de uso: Este algoritmo es útil en situaciones donde necesitas seleccionar una muestra aleatoria de un conjunto de números, especialmente cuando el tamaño del conjunto es grande y la eficiencia es importante. Un ejemplo concreto es en bases de datos distribuidas, como CockroachDB, donde se utiliza para seleccionar un subconjunto de claves de partición para operaciones de prueba o diagnóstico. También puede ser útil en simulaciones, análisis de datos y otras aplicaciones donde se requiere una muestra aleatoria.

Consideraciones: Aunque el algoritmo es eficiente, su intuición es sutil y puede ser difícil de comprender completamente. No es tan intuitivo como otros algoritmos de muestreo más comunes. Además, la implementación requiere el uso de un generador de números aleatorios, cuya calidad puede afectar la aleatoriedad de la muestra. No existen alternativas directas que ofrezcan la misma eficiencia y propiedades de distribución uniforme con una implementación tan concisa.