webentwicklung-frage-antwort-db.com.de

Erstellen Sie eine große zufällige boolesche Matrix mit numpy

Ich versuche, eine riesige boolean-Matrix zu erstellen, die zufällig mit True und False mit einer bestimmten Wahrscheinlichkeit p gefüllt wird. Zuerst habe ich diesen Code verwendet:

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

Leider scheint es für diese große N nicht zu enden. Also habe ich versucht, es in die Generierung der einzelnen Zeilen aufzuteilen: 

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)

Jetzt passiert etwas Seltsames (zumindest bei mir Gerät): Die ersten ~ 1100 Zeilen werden sehr schnell generiert - aber danach wird der Code furchtbar langsam. Warum passiert dies? Was vermisse ich hier? Gibt es bessere Möglichkeiten, eine große Matrix zu erstellen, die True Einträge mit Wahrscheinlichkeit p und False Einträge mit Wahrscheinlichkeit 1-p enthält?

Edit : Da viele von Ihnen angenommen haben, dass RAM ein Problem sein wird: Da das Gerät, auf dem der Code ausgeführt wird, fast 500 GB RAM hat, ist dies kein Problem.

15
FlashTek

Das Problem ist Ihr RAM, die Werte werden beim Erstellen im Speicher abgelegt. Ich habe diese Matrix mit dem folgenden Befehl erstellt:

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

Ich habe ein AWS i3 Instanz mit 64 GB RAM und 8 Kernen. Um diese Matrix zu erstellen, zeigt htop, dass sie ~ 20 GB RAM beansprucht. Hier ein Benchmark, falls es Sie interessiert:

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

Beachten Sie, dass die Maskenmethode in Spitzenzeiten nur ~ 9 GB RAM) beansprucht.

Bearbeiten: Die erste Methode löscht das RAM nach Abschluss des Vorgangs, wobei die Funktionsmethode alles beibehält.

10
aws_apprentice

Also habe ich versucht, es in die Generierung der einzelnen Zeilen aufzuteilen:

Die Funktionsweise von np.random.choice besteht darin, zunächst für jede Zelle Ihrer Daten einen float64 in [0, 1) zu generieren und diesen dann mit np.search_sorted in einen Index in Ihrem Array zu konvertieren. Diese Zwischendarstellung ist achtmal größer als das boolesche Array!

Da Ihre Daten boolesch sind, können Sie den Faktor zwei beschleunigen

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

Was Sie natürlich in Ihrer Looping-Lösung verwenden könnten

Es scheint, als könnte np.random.choice hier etwas puffern - vielleicht möchten Sie ein Problem gegen numpy einreichen.

Eine andere Option wäre, float32s anstelle von float64s zu versuchen und zu generieren. Ich bin nicht sicher, ob Numpy das jetzt tun kann, aber Sie könnten die Funktion anfordern.

3
Eric

Eine andere Möglichkeit könnte sein, sie in einem Stapel zu erzeugen (d. H. Viele Unterarrays zu berechnen und ganz am Ende zu stapeln). Bedenken Sie jedoch, dass Sie nicht ein Array (mask) in einer for-Schleife aktualisieren, wie es bei OP der Fall ist. Dies würde das gesamte Array zwingen, während jeder Indexierungsaktualisierung in den Hauptspeicher zu laden.

Beispiel: Um 30000x30000 zu erhalten, über 9000 100x100 separate Arrays zu verfügen, aktualisieren Sie jedes 100x100-Array entsprechend in einer for-Schleife und stapeln diese 9000-Arrays schließlich in einem riesigen Array. Dies würde definitiv nicht mehr als 4 GB RAM benötigen und wäre auch sehr schnell.

Minimales Beispiel:

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)
0
kmario23