7

Niedawno odpowiedział na THIS pytanie, które chciał mnożenie 2 wymieniono niektóre użytkownik zaproponował następujący sposób przy użyciu numpy, obok kopalni, które myślę, że to jest właściwy sposób:Dlaczego rozumienie list jest dużo szybsze niż numpy w przypadku mnożenia tablic?

(a.T*b).T 

Ponadto stwierdziliśmy, że aray.resize() ma takie same wydajność w ten sposób. jakiś sposób inna odpowiedź sugerowane rozwiązanie używając listowych:

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

Ale po benchmarku Widziałem, że lista zrozumieniem wykonuje bardzo szybciej niż numpy:

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") 

wynik:

first: 1.49778485298 
second : 7.43547797203 

Jak widać numpy jest około 5 razy szybszy. ale najbardziej zaskakujące było to, że jej szybciej bez użycia transpozycji, oraz do następującego kodu:

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

a*b 

Lista rozumienie nadal był 5 raz faster.So oprócz tego stopnia, że ​​listowych wykonuje w C tutaj użyliśmy 2 zagnieżdżonych pętli i funkcja zip Więc jaki może być powód? Czy to z powodu operacji * w numpy?

Należy również zauważyć, że nie ma problemu z timeit tutaj wstawiłem część import w setup.

ja też próbowałem z większymi Arras, różnica staje się mniejsze, ale nadal nie ma sensu:

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") 

wynik:

first: 10.7480301857 
second : 13.1278889179 
+2

.... Spróbuj dużo większych tablic? – NightShadeQueen

+0

@NightShadeQueen Próbowałem, że nadal ten sam wynik – Kasramvd

+0

@Kasramvd jak dużo większy próbowałeś? – Falmarri

Odpowiedz

12

utworzenia tablic numpy jest znacznie wolniejsze niż tworzenie list:

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 

Nie może również koszty stałe ponoszone przez NumPy funkcja zwraca befor Mięso z obliczeń może być wykonane przez szybką leżącą pod spodem funkcję C/Fortran. Może to obejmować zapewnienie, że dane wejściowe są tablicami NumPy,

Te ustawienia/koszty stałe są o czym należy pamiętać, zanim założymy, że NumPy są z natury rzeczy szybsze niż rozwiązania czysto Python. NumPy świeci gdy skonfigurowaniu duże tablice raz a następnie wykonać wiele operacji szybko NumPy na tablicach. Może nie osiągnąć lepszych wyników niż czysty Python, jeśli tablice są małe , ponieważ koszt konfiguracji może przewyższać korzyści z odciążenia obliczeń dla skompilowanych funkcji C/Fortran. W przypadku małych tablic po prostu może nie być wystarczających obliczeń, aby to było tego warte.


Jeśli zwiększyć rozmiar tablic nieco i przenieść tworzenia tablic do ustawień, a następnie NumPy może być znacznie szybciej niż czysta 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')) 

rentowności

s1: 4.6990 
s2: 0.1224 
s3: 0.1234 
+0

Problem polega na tym, że test tutaj obejmował tworzenie struktur danych, a po usunięciu "numpy" byłby rzeczywiście szybszy? – TigerhawkT3

+0

Tak, myślę, że to jest powód, ponieważ kiedy użyłem tablicy numpy w zrozumieniu listy, to robi się wolniej niż w przypadku numpy! – Kasramvd

+0

Jakiej powłoki/interpretera używasz, gdzie możesz zrobić '% timeit python_expression'? –