2010-05-05 29 views
6

Estoy buscando un generador de números aleatorios que pueda estar predispuesto. Por ejemplo, digo que quiero un número aleatorio entre 1-5, con el ser probabilidad:Generador de números aleatorios sesgado

1: Viene hasta 20% del tiempo
2: Viene hasta 10% del tiempo
3: Viene hasta 40 % de las veces
4: Viene hasta el 25% del tiempo
5: Viene un 5% del tiempo

¿hay algo en la biblioteca estándar, u otras bibliotecas por ahí que haría esto? Alternativamente, ¿hay una forma eficiente de hacerlo yo mismo?

+10

espero ¡no estás escribiendo software para casinos! – Alan

+2

Jaja no, estoy seguro de que un casino contrataría a alguien un poco más inteligente. – cmptrer

+1

De ayer: http://stackoverflow.com/questions/2772882/c-picking-a-random-item-based-on-probabilities y que era un duplicado de scads de versiones anteriores de la misma pregunta (que soy demasiado perezoso para encontrar). La palabra que puede haber perdido en la búsqueda es "discreta", lo cual es importante ya que varias de las respuestas a continuación se aplican mejor a las distribuciones continuas. – dmckee

Respuesta

9

La biblioteca de números aleatorios de Boost proporciona la capacidad de especificar diferentes distribuciones de formas para su generador. Es una gran biblioteca - ver http://www.boost.org/doc/libs/1_42_0/libs/random/index.html.

+1

Sí, ¡no reinvente la rueda! –

+5

Algún día voy a comenzar a usar Boost. Algún día. –

+0

Simplemente carece de una documentación adecuada ... sería genial saber cuáles son los conceptos necesarios para el motor y la distribución para poder crear uno propio sin ingeniería inversa de la biblioteca :( –

15

para su problema, sólo debes elegir un elemento aleatorio de esta lista de manera uniforme:

[1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5] 

En general, marque esta respuesta: Weighted random numbers


En TR1 y C++ 0x, hay <random> header que contiene el discrete_distribution class para generar tales números, entre otros.

Es posible que también desee comprobar GSL que contiene mucho más random distributions (y generadores de números aleatorios) que la biblioteca estándar <random>. (Sin embargo, tenga en cuenta que GSL utiliza GPLv3.)

+2

Tal vez debería haber explicado mi situación real un poco mejor. Lo que realmente necesito será un número aleatorio entre 1-50,000ish. Crear una lista que por mucho tiempo parece innecesaria e innecesaria. Perdón por la confusion. – cmptrer

+6

Es por eso que una buena ingeniería requiere un conjunto adecuado de requisitos. Usted pidió el caso simple y obtuvo la respuesta (correcta) simple. –

12

La mejor manera es probable que acaba de tomar el generador aleatorio imparcial normal, a continuación, volver basado en el intervalo de su valor cae en.

Sólo una sentencia if que da 1 para 0: 0,2, 2 para 0,2: 0,3, 3 para 0,3: 0,7, 4 de 0,7: 0,95 y 5 por 0,95: 1. Lo mejor es hacer que el límite inferior o superior del intervalo sea inclusivo y el otro exclusivo.

int biasedRandom(){ 
double i = randomNumber(); 
if(i<= 0.2){return 1;} 
else if(i <= 0.3){return 2;} 
else if(i <= 0.7){return 3;} 
else if(i <= 0.95){return 4;} 
else{return 5;} 
} 

Algo así.

+2

Si tiene que controlar un montón de intervalos, lo que debe hacer es crear una matriz de distribución acumulativa (no estaba seguro de cómo llamarla) y hacer una búsqueda binaria cada vez para encontrar el número que fue generado. –

+2

Parece que este generador devolverá 5 siempre. Se necesitan dobles/flotantes y algunas otras operaciones matemáticas a menos que randomNumber() devuelva un valor 0-1. – Xorlev

+0

Sí, tenías razón, me hubiera dado 5 todas las veces, no fue mi intención hacer una int, fue un error. Gracias por mencionarlo. – AaronM

0

¿Por qué no sólo tiene que utilizar un generador de números aleatorios regular que volver número entre 0,0 y 1,0, y se envuelve con otra función que devuelve un número de acuerdo a sus necesidades?

como

double biased (double seed) { 
if (seed >= 0.0 && seed <0.2) return 1; 
else if ... 
} 
+2

No utilizaría 'seed' como identificador de un número generado aleatoriamente, es confuso ... –

+0

¿Por qué no? La función C rand también toma una semilla, en la mayoría de los casos, la hora del sistema. Tan sesgada es una función que genera un número aleatorio basado en una semilla. – DaClown

0

Lanzar un azar número real x en [0,1], if 0< x<0.2 return 1, if 0.2<x <0.3 return 2, etc.

Ver here para el problema general.

0

Kenny dio una respuesta adecuada a la medida de su distribución de frecuencias en particular.

La respuesta más general trabaja con un CDF - función de distribución acumulativa - para los datos, y utiliza un número aleatorio uniforme para recoger un valor dentro de la distribución.

5

Lo que usted describe es la implementación de un generador de números aleatorios que se basa en una distribución de probabilidad particular. Por ejemplo, dibujar números de una distribución gaussiana debe dibujar números aleatorios de manera que la probabilidad de un sorteo particular, x sea proporcional a alt text http://upload.wikimedia.org/math/1/8/4/184fa5540b76903b1653d9f83912265d.png.

En general, el enfoque consiste en extraer de una distribución aleatoria uniforme y luego seleccionar el valor de la función de distribución acumulativa (CDF) de distribución deseada en esa ubicación dibujada. En el caso de un gaussiano normal, dibuje un número aleatorio, x de una distribución uniforme (esto es lo que deberían dar los generadores de números aleatorios estándar) y luego elija alt text como el valor aleatorio distribuido de Gauss. Para su caso, la CDF que usted describe es una función de escalón continuo paso por paso que podría implementarse utilizando cualquiera de las muchas (correctas) respuestas que ya ha recibido.

Por supuesto, esto es todo trivial. Lo que debería hacer es utilizar una biblioteca que ya maneja esto para usted. Las estadísticas y la generación de números aleatorios no son triviales y no hay necesidad de reinventar la rueda. Vea la respuesta de Neil (y revise la biblioteca Boost random number).

4

Llegando tarde a la fiesta en este caso. Aquí está la respuesta C++ 0x:

#include <iostream> 
#include <random> 
#include <iterator> 

int main() 
{ 
    // Set up distribution 
    double interval[] = {1, 2, 3, 4, 5, 6}; 
    double weights[] = { .2, .1, .4, .25, .05}; 
    std::piecewise_constant_distribution<> dist(std::begin(interval), 
               std::end(interval), 
               std::begin(weights)); 
    // Choose generator 
    std::mt19937 gen; // seed as wanted 
    // Demonstrate by pouring into avg[rand-1] 
    const unsigned N = 1000000; 
    double avg[sizeof(weights)/sizeof(weights[0])] = {0}; 
    for (unsigned i = 0; i < N; ++i) 
     avg[static_cast<unsigned>(dist(gen)) - 1]++; 
    // Comute averages 
    for (double* i = std::begin(avg); i < std::end(avg); ++i) 
     *i /= N; 
    // Display 
    for (unsigned i = 1; i <= sizeof(avg)/sizeof(avg[0]); ++i) 
     std::cout << "avg[" << i << "] = " << avg[i-1] << '\n'; 
} 

que para mí salidas:

avg[1] = 0.199779 
avg[2] = 0.100002 
avg[3] = 0.400111 
avg[4] = 0.250257 
avg[5] = 0.049851 
+0

+1 ¡Excelente respuesta! –

0
#include <boost/random/discrete_distribution.hpp> 
#include <boost/random/mersenne_twister.hpp> 
#include <boost/random/variate_generator.hpp> 

#include <iostream> 

int main() 
{ 

    unsigned int seed = 42; 
    boost::mt19937 generator(seed); 

    // return 0 with probability 10% 
    //  1     40% 
    //  2     50% 
    boost::random::discrete_distribution<int> custom_dist{1,4,5}; 

    boost::variate_generator<boost::mt19937&, 
    boost::random::discrete_distribution<int> > rndn(generator, custom_dist); 

    for (unsigned int i = 0; i<10000; i++) { 
    std::cout << rndn() << std::endl; 
    } 

    return 0; 

} 

Y aquí es una representación gráfica del resultado:

Output

Cuestiones relacionadas