7

Vor kurzem habe ich zu THIS Frage beantwortet, die die Vermehrung von 2 Listen wollte, schlug einige Benutzer die folgende Art und Weise numpy verwenden, neben meiner, die ich denke, der richtige Weg ist:Warum ist das Verständnis von Listen viel schneller als das Multiplizieren von Arrays?

(a.T*b).T 

Auch fand ich, dass aray.resize() hat eine gleiche Leistung wie das. eine Möglichkeit vorgeschlagen, eine andere Antwort, eine Lösung mit Liste Verständnis:

[[m*n for n in second] for m, second in zip(b,a)] 

Aber nach dem Benchmark sah ich, dass die Liste Verständnis als numpy sehr schneller ausführt:

from timeit import timeit 

s1=""" 
a=[[2,3,5],[3,6,2],[1,3,2]] 
b=[4,2,1] 

[[m*n for n in second] for m, second in zip(b,a)] 
""" 
s2=""" 
a=np.array([[2,3,5],[3,6,2],[1,3,2]]) 
b=np.array([4,2,1]) 

(a.T*b).T 
""" 

print ' first: ' ,timeit(stmt=s1, number=1000000) 
print 'second : ',timeit(stmt=s2, number=1000000,setup="import numpy as np") 

Ergebnis:

first: 1.49778485298 
second : 7.43547797203 

Wie Sie sehen können, ist numpy ungefähr 5 mal schneller. aber die meisten überraschend war, dass seine schneller ohne transponieren zu verwenden und für folgenden Code:

a=np.array([[2,3,5],[3,6,2],[1,3,2]]) 
b=np.array([[4],[2],[1]]) 

a*b 

Die Liste Verständnis noch 5 Mal faster.So war neben diesem Punkt, die Listenkomprehensionen in C führt hier verwenden wir zwei verschachtelte Schleife und eine zip Funktion Was kann der Grund sein? Ist es wegen der Operation * in numpy?

Beachten Sie auch, dass es kein Problem mit timeit gibt hier putted ich den import Teil in setup.

Ich versuchte es auch mit größeren arras, der Unterschied wird geringer, aber immer noch keinen Sinn macht:

s1=""" 
a=[[2,3,5],[3,6,2],[1,3,2]]*10000 
b=[4,2,1]*10000 

[[m*n for n in second] for m, second in zip(b,a)] 
""" 
s2=""" 
a=np.array([[2,3,5],[3,6,2],[1,3,2]]*10000) 
b=np.array([4,2,1]*10000) 

(a.T*b).T 

""" 



print ' first: ' ,timeit(stmt=s1, number=1000) 
print 'second : ',timeit(stmt=s2, number=1000,setup="import numpy as np") 

Ergebnis:

first: 10.7480301857 
second : 13.1278889179 
+2

.... Versuchen Sie viel größere Arrays? – NightShadeQueen

+0

@NightShadeQueen Ich versuchte das immer noch das gleiche Ergebnis – Kasramvd

+0

@Kasramvd wie viel größer haben Sie versucht? – Falmarri

Antwort

12

Erstellung von numpy Arrays ist viel langsamer als die Schaffung von Listen:

In [153]: %timeit a = [[2,3,5],[3,6,2],[1,3,2]] 
1000000 loops, best of 3: 308 ns per loop 

In [154]: %timeit a = np.array([[2,3,5],[3,6,2],[1,3,2]]) 
100000 loops, best of 3: 2.27 µs per loop 

kann es auch durch NumPy entstandenen Fixkosten Funktionsaufrufe vor dem Das Fleisch der Berechnung kann durch eine schnelle zugrunde liegende C/Fortran-Funktion durchgeführt werden. Dazu gehören die NumPy-Arrays

Diese Setup/Fixkosten sind etwas zu beachten, bevor NumPy Lösungen sind von Natur aus schneller als reine Python-Lösungen. NumPy leuchtet, wenn Sie eingerichtet große Arrays einmal und dann viele schnell NumPy Operationen auf den Arrays durchzuführen. Wenn die Arrays klein sind, , da die Setup-Kosten den Vorteil überwiegen können, die Berechnungen zu kompilierten C/Fortran-Funktionen zu entladen, kann es sein, reines Python zu übertreffen. Für kleine Arrays gibt es einfach nicht genug Berechnungen, um es sich zu lohnen.


Wenn Sie die Größe der Arrays ein wenig erhöhen, und die Schaffung der Arrays in das Setup bewegen, dann kann NumPy viel schneller als reiner Python:

import numpy as np 
from timeit import timeit 

N, M = 300, 300 

a = np.random.randint(100, size=(N,M)) 
b = np.random.randint(100, size=(N,)) 

a2 = a.tolist() 
b2 = b.tolist() 

s1=""" 
[[m*n for n in second] for m, second in zip(b2,a2)] 
""" 

s2 = """ 
(a.T*b).T 
""" 

s3 = """ 
a*b[:,None] 
""" 

assert np.allclose([[m*n for n in second] for m, second in zip(b2,a2)], (a.T*b).T) 
assert np.allclose([[m*n for n in second] for m, second in zip(b2,a2)], a*b[:,None]) 

print 's1: {:.4f}'.format(
    timeit(stmt=s1, number=10**3, setup='from __main__ import a2,b2')) 
print 's2: {:.4f}'.format(
    timeit(stmt=s2, number=10**3, setup='from __main__ import a,b')) 
print 's3: {:.4f}'.format(
    timeit(stmt=s3, number=10**3, setup='from __main__ import a,b')) 

Ausbeuten

s1: 4.6990 
s2: 0.1224 
s3: 0.1234 
+0

Also, das Problem ist, dass der Test hier die Erstellung der Datenstrukturen beinhaltete, und, damit entfernt, wäre "numpy" tatsächlich schneller? – TigerhawkT3

+0

Ja, ich denke, das ist der Grund, denn wenn ich im Listenverständnis ein numpliges Array verwende, wird es langsamer als dieser numpige Ansatz! – Kasramvd

+0

Welche Shell/Interpreter benutzen Sie, wo Sie '% timeit python_expression' machen können? –