Tengo un archivo con algunas probabilidades para diferentes valores, por ejemplo:
1 0.1
2 0.05
3 0.05
4 0.2
5 0.4
6 0.2
Me gustaría generar números aleatorios usando esta distribución. ¿Existe un módulo existente que maneje esto? Es bastante simple codificar por su cuenta (cree la función de densidad acumulativa, genere un valor aleatorio [0,1] y elija el valor correspondiente), pero parece que esto debería ser un problema común y probablemente alguien ha creado una función / módulo para eso.
Necesito esto porque quiero generar una lista de cumpleaños (que no siguen ninguna distribución en el random
módulo estándar ).
random.choice()
? Construye la lista maestra con el número adecuado de ocurrencias y elige una. Esta es una pregunta duplicada, por supuesto.Respuestas:
scipy.stats.rv_discrete
puede ser lo que quieras Puede proporcionar sus probabilidades a través delvalues
parámetro. Luego puede usar elrvs()
método del objeto de distribución para generar números aleatorios.Como señaló Eugene Pakhomov en los comentarios, también puede pasar un
p
parámetro de palabra clave anumpy.random.choice()
, p. Ej.Si está utilizando Python 3.6 o superior, puede usarlo
random.choices()
desde la biblioteca estándar; consulte la respuesta de Mark Dickinson .fuente
numpy.random.choice()
es casi 20 veces más rápido.numpy.random.choice(numpy.arange(1, 7), p=[0.1, 0.05, 0.05, 0.2, 0.4, 0.2])
Desde Python 3.6, hay una solución para esto en la biblioteca estándar de Python, a saber
random.choices
.Ejemplo de uso: configuremos una población y pesos que coincidan con los de la pregunta del OP:
Ahora
choices(population, weights)
genera una sola muestra:El argumento opcional de solo palabras clave
k
permite solicitar más de una muestra a la vez. Esto es valioso porque hay algo de trabajo preparatorio querandom.choices
debe hacerse cada vez que se llama, antes de generar muestras; Al generar muchas muestras a la vez, solo tenemos que hacer ese trabajo preparatorio una vez. Aquí generamos un millón de muestras y las utilizamoscollections.Counter
para verificar que la distribución que obtenemos coincida aproximadamente con los pesos que dimos.fuente
Una ventaja de generar la lista usando CDF es que puede usar la búsqueda binaria. Si bien necesita O (n) tiempo y espacio para el preprocesamiento, puede obtener k números en O (k log n). Como las listas normales de Python son ineficientes, puede usar el
array
módulo.Si insiste en un espacio constante, puede hacer lo siguiente; O (n) tiempo, O (1) espacio.
fuente
l[-1]
devuelve el último elemento de la lista?Tal vez sea un poco tarde. Pero puedes usar
numpy.random.choice()
, pasando elp
parámetro:fuente
random.choice()
, vea los comentarios.numpy.random.choice()
es completamente diferenterandom.choice()
y admite distribución de probabilidad.(OK, sé que estás pidiendo una envoltura retráctil, pero tal vez esas soluciones locales simplemente no fueron lo suficientemente breves para tu gusto. :-)
Pseudoconfirmé que esto funciona mirando la salida de esta expresión:
fuente
i
no es un objeto.Escribí una solución para extraer muestras aleatorias de una distribución continua personalizada .
Necesitaba esto para un caso de uso similar al suyo (es decir, generar fechas aleatorias con una distribución de probabilidad dada).
Solo necesitas la función
random_custDist
y la líneasamples=random_custDist(x0,x1,custDist=custDist,size=1000)
. El resto es decoración ^^.El rendimiento de esta solución es mejorable con seguridad, pero prefiero la legibilidad.
fuente
Haga una lista de artículos, en función de sus
weights
:Una optimización puede ser normalizar cantidades por el máximo divisor común, para hacer que la lista de objetivos sea más pequeña.
Además, esto podría ser interesante.
fuente
Otra respuesta, probablemente más rápido :)
fuente
Verificación:
fuente
basado en otras soluciones, genera una distribución acumulativa (como entero o flotante, lo que quiera), luego puede usar bisect para hacerlo más rápido
este es un ejemplo simple (usé enteros aquí)
la
get_cdf
función lo convertiría de 20, 60, 10, 10 en 20, 20 + 60, 20 + 60 + 10, 20 + 60 + 10 + 10ahora elegimos un número aleatorio hasta 20 + 60 + 10 + 10 usando
random.randint
luego usamos bisect para obtener el valor real de una manera rápidafuente
es posible que desee echar un vistazo a las distribuciones de muestreo aleatorio NumPy
fuente
Ninguna de estas respuestas es particularmente clara o simple.
Aquí hay un método claro y simple que garantiza que funcione.
acumulate_normalize_probabilities toma un diccionario
p
que asigna símbolos a probabilidades O frecuencias. Produce una lista utilizable de tuplas para hacer la selección.Rendimientos:
Por que funciona
El paso de acumulación convierte cada símbolo en un intervalo entre sí mismo y la probabilidad o frecuencia de los símbolos anteriores (o 0 en el caso del primer símbolo). Estos intervalos se pueden usar para seleccionar (y, por lo tanto, muestrear la distribución proporcionada) simplemente recorriendo la lista hasta que el número aleatorio en el intervalo 0.0 -> 1.0 (preparado anteriormente) sea menor o igual al punto final del intervalo del símbolo actual.
los normalización nos libera de la necesidad de asegurarnos de que todo tenga algún valor. Después de la normalización, el "vector" de probabilidades suma 1.0.
El resto del código para la selección y la generación de una muestra arbitrariamente larga de la distribución se encuentra a continuación:
Uso:
fuente
Aquí hay una forma más efectiva de hacer esto:
Simplemente llame a la siguiente función con su matriz de 'pesos' (asumiendo los índices como los elementos correspondientes) y el no. de muestras necesarias. Esta función se puede modificar fácilmente para manejar el par ordenado.
Devuelve índices (o elementos) muestreados / seleccionados (con reemplazo) usando sus respectivas probabilidades:
Una breve nota sobre el concepto utilizado en el ciclo while. Reducimos el peso del elemento actual de beta acumulativo, que es un valor acumulativo construido de manera uniforme al azar, e incrementamos el índice actual para encontrar el elemento, cuyo peso coincide con el valor de beta.
fuente