J'essaie de créer une énorme matrice boolean
qui est remplie de façon aléatoire avec True
et False
avec une probabilité donnée p
. Au début, j'ai utilisé ce code:
N = 30000
p = 0.1
np.random.choice(a=[False, True], size=(N, N), p=[p, 1-p])
Mais malheureusement, cela ne semble pas se terminer pour ce gros N
. J'ai donc essayé de le scinder en plusieurs générations:
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)
Maintenant, il se passe quelque chose d'étrange (du moins sur le périphérique): les premières ~ 1100 lignes sont générées très rapidement - mais après cela, le code devient horriblement lent. Pourquoi cela arrive-t-il? Qu'est-ce qui me manque ici? Existe-t-il de meilleurs moyens de créer une grande matrice comportant des entrées True
avec une probabilité p
et des entrées False
avec une probabilité 1-p
?
Edit : Comme beaucoup d’entre vous avez supposé que la RAM poserait un problème: comme l’appareil qui exécutera le code dispose de presque 500 Go de RAM, cela ne posera pas de problème.
J'ai donc essayé de le scinder en plusieurs générations:
La façon dont fonctionne np.random.choice
consiste tout d'abord à générer un float64
dans [0, 1)
pour chaque cellule de vos données, puis à le convertir en un index de votre tableau à l'aide de np.search_sorted
. Cette représentation intermédiaire est 8 fois plus grande que le tableau booléen!
Puisque vos données sont booléennes, vous pouvez obtenir un facteur de deux accélération avec
np.random.Rand(N, N) > p
Ce que vous pourriez naturellement utiliser dans votre solution de bouclage
Il semble que np.random.choice
pourrait faire quelque chose de tampon ici - vous voudrez peut-être déposer un problème contre numpy.
Une autre option serait d’essayer de générer float32
s au lieu de float64
s. Je ne sais pas si numpy peut le faire maintenant, mais vous pouvez demander la fonctionnalité.
Une autre possibilité pourrait être de le générer par lot (c’est-à-dire calculer plusieurs sous-tableaux et les empiler à la fin). Mais envisagez de ne pas mettre à jour un tableau (mask
) dans une boucle for
comme le fait OP. Cela obligerait l'ensemble du tableau à se charger en mémoire principale lors de chaque mise à jour d'indexation.
Par exemple, pour obtenir 30000x30000
, créez 9000 100x100
tableaux séparés, mettez à jour chacun de ces tableaux 100x100
dans une boucle for
et empilez ces 9000 tableaux dans un tableau géant. Cela n’aurait certainement pas besoin de plus de 4 Go de RAM et serait également très rapide.
Exemple minimal:
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)