números - generar numeros python
La manera más rápida de generar más de 1,000,000 de números aleatorios en python (6)
Actualmente estoy escribiendo una aplicación en python que necesita generar una gran cantidad de números aleatorios, FAST. Actualmente tengo un esquema en marcha que utiliza numpy para generar todos los números en un lote gigante (alrededor de ~ 500,000 a la vez). Si bien esto parece ser más rápido que la implementación de python. Todavía lo necesito para ir más rápido. ¿Algunas ideas? Estoy abierto a escribirlo en C e insertarlo en el programa o hacer lo que sea necesario.
Restricciones en los números aleatorios:
- Un conjunto de 7 números que pueden tener diferentes límites:
- por ejemplo: [0-X1, 0-X2, 0-X3, 0-X4, 0-X5, 0-X6, 0-X7]
- Actualmente estoy generando una lista de 7 números con valores aleatorios de [0-1) y luego multiplicándolos por [X1..X7]
- Un conjunto de 13 números que suman hasta 1.
- Actualmente solo generando 13 números y luego dividiendo por su suma.
¿Algunas ideas? ¿El cálculo previo de estos números y su almacenamiento en un archivo lo haría más rápido?
¡Gracias!
Como ya han numpy
, numpy
es un muy buen comienzo, rápido y fácil de usar.
Si necesita números aleatorios en una escala masiva, considere eas-ecb o rc4. Ambos pueden ser paralelizados, debe alcanzar el rendimiento en varios GB / s.
Hacer que tu código se ejecute en paralelo ciertamente no podría hacer daño. Intenta adaptarlo para SMP con Parallel Python
Intente r = 1664525*r + 1013904223
de "un generador aún más rápido" en "Recetas numéricas en C" 2da edición, Press et al., isbn 0521431085, p. 284.
np.random es ciertamente "más aleatorio"; Ver generador congruente lineal .
En Python, use np.uint32
como este:
python -mtimeit -s ''
import numpy as np
r = 1
r = np.array([r], np.uint32)[0] # 316 py -> 16 us np
# python longs can be arbitrarily long, so slow
'' ''
r = r*1664525 + 1013904223 # NR2 p. 284
''
Para generar grandes bloques a la vez:
# initialize --
np.random.seed( ... )
R = np.random.randint( 0, np.iinfo( np.uint32 ).max, size, dtype=np.uint32 )
...
R *= 1664525
R += 1013904223
Puedes acelerar un poco las cosas de lo que mtrw publicó anteriormente solo haciendo lo que describiste inicialmente (generando un montón de números aleatorios y multiplicando y dividiendo en consecuencia) ...
Además, probablemente ya lo sepa, pero asegúrese de realizar las operaciones en el lugar (* =, / =, + =, etc.) cuando trabaje con matrices de gran tamaño. Hace una gran diferencia en el uso de memoria con arreglos grandes, y también dará un aumento de velocidad considerable.
In [53]: def rand_row_doubles(row_limits, num):
....: ncols = len(row_limits)
....: x = np.random.random((num, ncols))
....: x *= row_limits
....: return x
....:
In [59]: %timeit rand_row_doubles(np.arange(7) + 1, 1000000)
10 loops, best of 3: 187 ms per loop
En comparación con:
In [66]: %timeit ManyRandDoubles(np.arange(7) + 1, 1000000)
1 loops, best of 3: 222 ms per loop
No es una gran diferencia, pero si estás realmente preocupado por la velocidad, es algo.
Solo para demostrar que es correcto:
In [68]: x.max(0)
Out[68]:
array([ 0.99999991, 1.99999971, 2.99999737, 3.99999569, 4.99999836,
5.99999114, 6.99999738])
In [69]: x.min(0)
Out[69]:
array([ 4.02099599e-07, 4.41729377e-07, 4.33480302e-08,
7.43497138e-06, 1.28446819e-05, 4.27614385e-07,
1.34106753e-05])
Del mismo modo, para su "filas suma a una" parte ...
In [70]: def rand_rows_sum_to_one(nrows, ncols):
....: x = np.random.random((ncols, nrows))
....: y = x.sum(axis=0)
....: x /= y
....: return x.T
....:
In [71]: %timeit rand_rows_sum_to_one(1000000, 13)
1 loops, best of 3: 455 ms per loop
In [72]: x = rand_rows_sum_to_one(1000000, 13)
In [73]: x.sum(axis=1)
Out[73]: array([ 1., 1., 1., ..., 1., 1., 1.])
Honestamente, incluso si vuelves a implementar las cosas en C, no estoy seguro de que puedas superar mucho en este caso ... ¡aunque podría estar muy equivocado!
Solo un rápido ejemplo de numpy
en acción:
data = numpy.random.rand(1000000)
No necesita bucle, puede pasar la cantidad de números que desea generar.
EDITAR Funciones creadas que devuelven el conjunto completo de números, no solo una fila a la vez. EDIT 2 Haga que las funciones sean más sintéticas (y más rápidas), agregue solución para la segunda pregunta
Para el primer conjunto de números, podría considerar numpy.random.randint
o numpy.random.uniform
, que toman parámetros high
y low
. La generación de una matriz de 7 x 1,000,000 de números en un rango específico parece tomar <0.7 segundos en mi máquina de 2 GHz:
def LimitedRandInts(XLim, N):
rowlen = (1,N)
return [np.random.randint(low=0,high=lim,size=rowlen) for lim in XLim]
def LimitedRandDoubles(XLim, N):
rowlen = (1,N)
return [np.random.uniform(low=0,high=lim,size=rowlen) for lim in XLim]
>>> import numpy as np
>>> N = 1000000 #number of randoms in each range
>>> xLim = [x*500 for x in range(1,8)] #convenient limit generation
>>> fLim = [x/7.0 for x in range(1,8)]
>>> aa = LimitedRandInts(xLim, N)
>>> ff = LimitedRandDoubles(fLim, N)
Esto devuelve números enteros en [0, xLim-1] o flota en [0, fLim). La versión entera tomó ~ 0.3 segundos, el doble ~ 0.66, en mi máquina de un solo núcleo de 2 GHz.
Para el segundo set, utilicé la sugerencia de @Joe Kingston.
def SumToOneRands(NumToSum, N):
aa = np.random.uniform(low=0,high=1.0,size=(NumToSum,N)) #13 rows by 1000000 columns, for instance
s = np.reciprocal(aa.sum(0))
aa *= s
return aa.T #get back to column major order, so aa[k] is the kth set of 13 numbers
>>> ll = SumToOneRands(13, N)
Esto lleva ~ 1,6 segundos.
En todos los casos, el result[k]
le da el k conjunto de datos.