Existe un algoritmo sencillo para seleccionar un artículo al azar, donde los artículos tienen pesos individuales:
1) calcula la suma de todos los pesos
2) elija un número aleatorio que sea 0 o mayor y sea menor que la suma de los pesos
3) revise los artículos uno a la vez, restando su peso de su número aleatorio, hasta que obtenga el artículo donde el número aleatorio es menor que el peso de ese artículo
Pseudocódigo que ilustra esto:
int sum_of_weight = 0;
for(int i=0; i<num_choices; i++) {
sum_of_weight += choice_weight[i];
}
int rnd = random(sum_of_weight);
for(int i=0; i<num_choices; i++) {
if(rnd < choice_weight[i])
return i;
rnd -= choice_weight[i];
}
assert(!"should never get here");
Esto debería ser sencillo de adaptar a sus contenedores de impulso y demás.
Si sus pesos rara vez se cambian, pero a menudo elige uno al azar, y siempre que su contenedor esté almacenando punteros a los objetos o tenga más de unas pocas docenas de elementos (básicamente, debe perfilar para saber si esto ayuda o dificulta) , luego hay una optimización:
Al almacenar la suma de peso acumulada en cada artículo, puede utilizar una búsqueda binaria para seleccionar el artículo correspondiente al peso de picking.
Si no conoce la cantidad de elementos de la lista, existe un algoritmo muy ordenado llamado muestreo de yacimientos que se puede adaptar para ponderar.
A Monte Carlo method called Russian roulette is used to choose one of these actions
aparece en cubos cuando se busca en Google. "algoritmo de la ruleta rusa". Sin embargo, se podría argumentar que todas estas personas tienen el nombre incorrecto.Respuesta actualizada a una pregunta anterior. Puede hacer esto fácilmente en C ++ 11 con solo std :: lib:
Salida en mi sistema:
Tenga en cuenta que la mayor parte del código anterior está dedicado solo a mostrar y analizar la salida. La generación real son solo unas pocas líneas de código. El resultado demuestra que se han obtenido las "probabilidades" solicitadas. Debe dividir la salida solicitada por 1.5, ya que eso es lo que suman las solicitudes.
fuente
std::discrete_distribution
lugar destd::piecewise_constant_distribution
hubiera sido aún mejor.Si sus pesos cambian más lentamente de lo que se dibujan, C ++ 11
discrete_distribution
será el más fácil:Sin embargo, tenga en cuenta que c ++ 11
discrete_distribution
calcula todas las sumas acumulativas en la inicialización. Por lo general, lo desea porque acelera el tiempo de muestreo por un costo O (N) único. Pero para una distribución que cambia rápidamente, incurrirá en un alto costo de cálculo (y memoria). Por ejemplo, si los pesos representan la cantidad de elementos que hay y cada vez que dibuja uno, lo elimina, probablemente querrá un algoritmo personalizado.La respuesta de Will https://stackoverflow.com/a/1761646/837451 evita esta sobrecarga, pero será más lenta de extraer que C ++ 11 porque no puede usar la búsqueda binaria.
Para ver que hace esto, puede ver las líneas relevantes (
/usr/include/c++/5/bits/random.tcc
en mi instalación de Ubuntu 16.04 + GCC 5.3):fuente
Lo que hago cuando necesito ponderar números es usar un número aleatorio para el peso.
Por ejemplo: necesito generar números aleatorios del 1 al 3 con los siguientes pesos:
Entonces uso:
Con esto, aleatoriamente tiene un 10% de probabilidades de ser 1, 30% de ser 2 y 60% de ser 3.
Puedes jugar con él según tus necesidades.
Espero poder ayudarte, ¡buena suerte!
fuente
Construya una bolsa (o std :: vector) de todos los elementos que se pueden recoger.
Asegúrese de que el número de cada artículo sea proporcional a su ponderación.
Ejemplo:
Así que tenga una bolsa con 100 artículos con 60 1, 35 2 y 5 3.
Ahora ordena aleatoriamente la bolsa (std :: random_shuffle)
Elija elementos de la bolsa secuencialmente hasta que esté vacía.
Una vez vacía, vuelva a aleatorizar la bolsa y comience de nuevo.
fuente
1,2,2
produce 1 1/3 del tiempo y 2 2/3. Aleatorice la matriz, elija el primero, digamos un 2, ahora el siguiente elemento que elija sigue la distribución de 1 1/2 del tiempo y 2 1/2 del tiempo. ¿Comprensión?Elija un número aleatorio en [0,1), que debería ser el operador predeterminado () para un aumento de RNG. Elija el elemento con la función de densidad de probabilidad acumulada> = ese número:
Donde random01 () devuelve un doble> = 0 y <1. Tenga en cuenta que lo anterior no requiere que las probabilidades sumen 1; los normaliza para ti.
p es simplemente una función que asigna una probabilidad a un elemento de la colección [inicio, finalización]. Puede omitirlo (o usar una identidad) si solo tiene una secuencia de probabilidades.
fuente
Implementé varios algoritmos aleatorios ponderados simples .
fuente