Cómo hacer una selección aleatoria ponderada discreta en tiempo constante

El algoritmo Alias ​​que mencionas en tu comentario es un enfoque inteligente, pero a menos que necesites una eficiencia extrema, vale más la pena. No me gusta por varias razones, pero es inteligente. Método de alias: Wikipedia tiene instrucciones simples paso a paso sobre cómo generar las tablas.

Si desea ver cómo funciona una vez que se generan las tablas, mire la tabla a continuación.

Multiplica una variable aleatoria U (0,1) por 16. La parte entera selecciona la columna de 0 a 15. Si la parte fraccionaria es mayor que el número en la fila P, devuelve el valor en la fila Y debajo de ella. Si la parte de la fracción es menor que el número en la fila P, simplemente devuelve la parte entera.

Entonces, si 16 veces su número aleatorio es 0.5, va a la columna 0 (la parte entera) y dado que la parte fraccionaria (0.5) es mayor que el número en la fila P (0), devuelve el número en la fila Y ( 5) Para cada parte entera, la tabla muestra qué números se devuelven con qué probabilidad. La suma de cada columna es 1, por supuesto. la suma de cada fila es 16 veces la probabilidad de que se devuelva cada número del 2 al 12, y como puede ver, corresponden a las probabilidades de dados correctas.

En la mayoría de las aplicaciones, puede aprovechar mejor la estructura de sus datos. Por ejemplo, la suma de dos dados se simula fácilmente como [int (6 * r1)] + [int (6 * r2)] + 2. Si generar dos números aleatorios es demasiado costoso, puede usar el mismo truco de multiplicar un número aleatorio por 6, tomar la parte entera, luego multiplicar la parte fraccional por 6 y tomar la parte entera de eso.

Creo que la solución ‘clásica’ a este problema sería usar una búsqueda binaria en tiempo O (logN) mientras se almacena la distribución acumulativa, usando memoria O (n). Puedo dar más detalles si es necesario, pero esto debería estar disponible en Internet en algún lugar.

Si realmente necesita tiempo constante (n debe ser bastante grande y / o debe estar haciendo MUCHAS consultas / simulaciones de desplazamiento), puede aumentar la memoria para acelerar la consulta. Digamos, tenga una matriz de tamaño M, y para cada valor j entre [0, M [precalcule el ‘rollo’ para la probabilidad 1 / j. Tenga en cuenta que es posible que M tenga que ser bastante grande si desea representar con precisión su distribución.

Sin embargo, en la práctica, casi siempre es mejor seguir el enfoque logN y, si es necesario, precalcule una gran cantidad de rollos aleatorios durante la noche, paralelícelo o comprométase con un valor menor de M (por ejemplo, 10000, distorsionando potencialmente su distribución de probabilidad pero necesita poca memoria).

La solución más elegante que conozco es construir un árbol Huffman para su distribución.

Editar: ¡el método al que se hace referencia en los comentarios de las preguntas es mucho más rápido y mejor! Aquí va de todos modos.

El número esperado de pasos para simularlo se encuentra dentro de uno de la entropía de la distribución. Esto nunca es más, y potencialmente mucho menos que el registro de la cantidad de resultados, que es el tiempo que necesita si realiza una búsqueda binaria en el cdf.

Como es habitual en un árbol Huffman, los resultados están en las hojas del árbol, y cada resultado está asociado con su probabilidad. Para esta aplicación, también necesitamos pesos de probabilidad en cada nodo interno del árbol: es decir, la suma de los pesos de sus hijos. Entonces, el nodo raíz obtiene el peso 1. (Normalmente, estos pesos de los nodos internos se mantienen durante la construcción del árbol Huffman de todos modos).

Aquí hay un seudocódigo para simular desde el árbol:

Seamos uniformemente aleatorios en [0,1].
Deje n señalar la raíz del árbol Huffman.
mientras n no es una hoja:
dejar w = peso (left_child (n))
si w establecer u = uw
conjunto n = right_child (n)
más
conjunto n = left_child (n)
terminara si
terminar mientras
resultado: resultado almacenado en la hoja n

El árbol Huffman es el árbol binario óptimo para este problema: producirá un resultado después del menor número de pasos en promedio.

More Interesting

¿Qué libro sobre algoritmos es una lectura obligada para un programador?

¿Existe algún estándar de algoritmo de programación de elevadores públicos?

¿Cuál es el número esperado de movimientos necesarios para terminar un juego de serpientes y escaleras?

¿Es suficiente el conocimiento del tamiz de Eratóstenes y la factorización prima al preparar los concursos de programación?

¿Qué es un programa Java para calcular el factorial de un número dado?

¿Cuáles son algunos de los códigos más pequeños que generan un número pseudoaleatorio?

¿El problema de las reinas N tiene al menos una solución por cada N> 3?

¿Cómo se almacenan los datos en un árbol binario?

¿Por qué ocurre el peor de los casos en Max-Heapify cuando la fila final del árbol está medio llena?

¿Cómo se puede calcular su edad en días? Necesito el algoritmo más simplificado para resolverlo.

¿Dónde puedo encontrar un algoritmo de relevancia marginal máxima en Python para la eliminación de redundancia en dos documentos?

¿Cómo se debe aprender la codificación, haciendo algoritmos, desde el nivel básico, dado que no tiene experiencia en codificación? (especialmente desde el punto de vista de la colocación y también dado el hecho de que me queda un año para que comience mi temporada de colocación).

Cómo diseñar algoritmos de aprendizaje automático desde cero

¿Cuál es la diferencia entre programación dinámica y recursividad?

¿Cómo se copia el contenido de un árbol de búsqueda binario que tiene emparejamientos K, V?