Crear gran matriz booleana aleatoria con numpy

Estoy tratando de crear una gran matriz boolean que se rellena aleatoriamente con True y False con una probabilidad dada p . Al principio usé este código:

 N = 30000 p = 0.1 np.random.choice(a=[False, True], size=(N, N), p=[p, 1-p]) 

Pero lamentablemente no parece terminar por esta gran N Así que traté de dividirlo en la generación de las filas individuales haciendo esto:

 N = 30000 p = 0.1 mask = np.empty((N, N)) for i in range (N): mask[i] = np.random.choice(a=[False, True], size=N, p=[p, 1-p]) if (i % 100 == 0): print(i) 

Ahora sucede algo extraño (al menos en mi dispositivo): las primeras ~ 1100 filas se generan muy rápidamente, pero después de eso, el código se vuelve terriblemente lento. ¿Por qué está pasando esto? ¿Qué extraño aquí? ¿Hay mejores maneras de crear una matriz grande que tenga entradas de True con probabilidad p y entradas de False con probabilidad 1-p ?

Edición : Como muchos de ustedes asumieron que la RAM será un problema: como el dispositivo que ejecutará el código tiene casi 500 GB de RAM, esto no será un problema.

El problema es su RAM, los valores se almacenan en la memoria a medida que se crea. Acabo de crear esta matriz usando este comando:

np.random.choice(a=[False, True], size=(N, N), p=[p, 1-p])

AWS i3 una instancia de AWS i3 con 64 GB de RAM y 8 núcleos. Para crear esta matriz, htop muestra que ocupa ~ 20 GB de RAM. Aquí hay un punto de referencia en caso de que te importa:

 time np.random.choice(a=[False, True], size=(N, N), p=[p, 1-p]) CPU times: user 18.3 s, sys: 3.4 s, total: 21.7 s Wall time: 21.7 s def mask_method(N, p): for i in range(N): mask[i] = np.random.choice(a=[False, True], size=N, p=[p, 1-p]) if (i % 100 == 0): print(i) time mask_method(N,p) CPU times: user 20.9 s, sys: 1.55 s, total: 22.5 s Wall time: 22.5 s 

Tenga en cuenta que el método de máscara solo ocupa ~ 9 GB de RAM en su punto máximo.

Edición: el primer método vacía la memoria RAM después de que se realiza el proceso, mientras que el método de la función retiene todo.

Así que traté de dividirlo en la generación de las filas individuales haciendo esto:

La forma en que funciona np.random.choice es generando primero un float64 en [0, 1) para cada celda de sus datos, y luego convirtiéndolo en un índice en su matriz usando np.search_sorted . ¡Esta representación intermedia es 8 veces más grande que la matriz booleana!

Dado que sus datos son booleanos, puede obtener un factor de dos de aceleración con

 np.random.rand(N, N) > p 

Que naturalmente, usted podría utilizar dentro de su solución de bucle

Parece que np.random.choice podría hacer con algunos np.random.choice aquí. Es posible que desee archivar un problema con numpy.

Otra opción sería intentar generar float32 s en lugar de float64 s. No estoy seguro de si Numpy puede hacer eso ahora, pero podría solicitar la función.

Otra posibilidad podría ser generarla en un lote (es decir, calcular muchos subarreglos y astackrlos al final). Pero, considere no actualizar una matriz ( mask ) en un bucle for como lo está haciendo OP. Esto obligaría a toda la matriz a cargarse en la memoria principal durante cada actualización de indexación.

En cambio, por ejemplo: para obtener 30000x30000 , tenga 9000 100x100 arreglos separados, actualice cada uno de estos arreglos de 100x100 en consecuencia en un bucle for y finalmente apile estos 9000 arreglos en un arreglo gigante. Esto definitivamente no necesitaría más de 4GB de RAM y sería muy rápido también.

Ejemplo mínimo:

 In [9]: a Out[9]: array([[0, 1], [2, 3]]) In [10]: np.hstack([np.vstack([a]*5)]*5) Out[10]: array([[0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [2, 3, 2, 3, 2, 3, 2, 3, 2, 3], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [2, 3, 2, 3, 2, 3, 2, 3, 2, 3], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [2, 3, 2, 3, 2, 3, 2, 3, 2, 3], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [2, 3, 2, 3, 2, 3, 2, 3, 2, 3], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [2, 3, 2, 3, 2, 3, 2, 3, 2, 3]]) In [11]: np.hstack([np.vstack([a]*5)]*5).shape Out[11]: (10, 10)