2010-08-03 7 views
7

Ich bin gerade dabei, numpy zu kennen, und ich bin beeindruckt von seinen Behauptungen von C-ähnlicher Effizienz mit Speicherzugriff in seinen ndarrays. Ich wollte die Unterschiede zwischen diesen und pythonischen Listen für mich selbst sehen, also führte ich einen schnellen Timing-Test durch, indem ich ein paar der gleichen einfachen Aufgaben ohne Numpy ausführte. Numpy deklassierte reguläre Listen um eine Größenordnung in der Zuweisung von und arithmetischen Operationen an Arrays, wie erwartet. Aber das Codesegment, identisch in beiden Tests dauerte etwa 1/8 eine Sekunde mit einer regelmäßigen Liste, und etwas mehr als 2,5 Sekunden mit numpy:Wie maximiere ich die Effizienz mit numpy Arrays?

file = open('timing.log','w') 
for num in a2: 
    if num % 1000 == 0: 
     file.write("Multiple of 1000!\r\n") 

file.close() 

Weiß jemand, warum dies auch sein mag, und wenn es ist eine andere Syntax, die ich für Operationen wie diese verwenden sollte, um besser zu nutzen, was der NDarray tun kann?

Dank ...

EDIT: Waynes Kommentar zu beantworten ... ich sie zeitlich sowohl wiederholt und in verschiedenen Ordnungen und bekam so ziemlich die gleichen Ergebnisse jedes Mal, so dass ich bezweifle, dass es ein anderer Prozess ist. Ich habe

start = time()
an der Spitze der Datei nach dem numpy Import und dann habe ich überall Anweisungen wie
print 'Time after traversal:\t',(time() - start)
.

+1

Können Sie zeigen, wie Sie die Zeit gemessen haben? Hast du versucht, deine Bestellung zu tauschen? Die Tatsache, dass Sie auf die Festplatte schreiben, verkompliziert das Timing-Problem (was wäre, wenn '[insert-process-here]' während des numpys-Tests mit höherer Priorität auf die Festplatte geschrieben wurde?) –

+0

Vielen Dank für alle Antworten! Alle waren informativ. Tut mir leid, ich habe nicht genug Ruf, um über sie abzustimmen! – pr0crastin8r

Antwort

9

a2 ist ein NumPy-Array, oder? Ein möglicher Grund, warum es in NumPy so lange dauern könnte (wenn die Aktivität anderer Prozesse dies nicht berücksichtigt, wie Wayne Werner vorgeschlagen hat), ist, dass Sie das Array mit einer Python-Schleife durchlaufen. Bei jedem Schritt der Iteration muss Python einen einzelnen Wert aus dem NumPy-Array abrufen und in eine Python-Ganzzahl konvertieren, was keine besonders schnelle Operation ist.

NumPy funktioniert viel besser, wenn Sie Operationen auf dem gesamten Array als eine Einheit durchführen können. In Ihrem Fall wäre eine Option (vielleicht nicht einmal das schnellste)

sein
file.write("Multiple of 1000!\r\n" * (a2 % 1000 == 0).sum()) 

Versuchen Sie das mal auf die pure-Python Äquivalent zu vergleichen,

file.write("Multiple of 1000!\r\n" * sum(filter(lambda i: i % 1000 == 0, a2))) 

oder

file.write("Multiple of 1000!\r\n" * sum(1 for i in a2 if i % 1000 == 0)) 
6

Ich bin nicht überrascht, dass NumPy mit Python-Einbauten schlecht arbeitet, wenn Sie Ihr Snippet verwenden. Ein großer Teil des Leistungsvorteils in NumPy ergibt sich aus den Schlingen zu vermeiden und stattdessen das Array durch Indizierung zuzugreifen:

In NumPy, ist es häufiger, so etwas zu tun:

A = NP.random.randint(10, 100, 100).reshape(10, 10) 
w = A[A % 2 == 0] 
NP.save("test_file.npy", w) 
+3

+1 für A [A% 2 == 0] Dies ist der Leitungstyp, den das OP verwenden möchte, außer natürlich mit 1000 statt 2. – tom10

5

Per-Element Zugang sehr langsam für numpy Arrays. Verwenden Sie Vektoroperationen:

$ python -mtimeit -s 'import numpy as np; a2=np.arange(10**6)' ' 
> sum(1 for i in a2 if i % 1000 == 0)' 
10 loops, best of 3: 1.53 sec per loop 

$ python -mtimeit -s 'import numpy as np; a2=np.arange(10**6)' ' 
> (a2 % 1000 == 0).sum()' 
10 loops, best of 3: 22.6 msec per loop 

$ python -mtimeit -s 'import numpy as np; a2= range(10**6)' ' 
> sum(1 for i in a2 if i % 1000 == 0)' 
10 loops, best of 3: 90.9 msec per loop