7

Recentemente ho risposto a THIS domanda che ha voluto la moltiplicazione delle 2 liste, qualche utente ha suggerito seguente modo utilizzando NumPy, al fianco di mia che credo sia il modo corretto:Perché la comprensione degli elenchi è molto più veloce di numpy per la moltiplicazione degli array?

(a.T*b).T 

Inoltre ho scoperto che aray.resize() ha una stessa prestazioni del genere. alcun modo un'altra risposta ha suggerito una soluzione che utilizza la lista di comprensione:

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

Ma dopo il punto di riferimento ho visto che la lista di comprensione esegue molto più velocemente di quanto 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") 

risultato:

first: 1.49778485298 
second : 7.43547797203 

Come puoi vedere, numpy è circa 5 volte più veloce. ma cosa più sorprendente è che il suo più veloce senza l'utilizzo di recepire, e per la seguente codice:

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

a*b 

La lista di comprensione era ancora 5 tempo faster.So oltre questo punto che di lista si esibisce in C qui abbiamo usato 2 ciclo nidificato e una funzione zip Quindi quale può essere la ragione? È a causa dell'operazione * in numpy?

Si noti inoltre che non vi sono problemi con timeit qui ho inserito la parte import in setup.

Ho anche provato con arazzi grandi, la differenza diventa inferiore ma ancora non ha senso:

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

risultato:

first: 10.7480301857 
second : 13.1278889179 
+2

.... Prova matrici molto più grandi? – NightShadeQueen

+0

@NightShadeQueen Ho provato ancora lo stesso risultato – Kasramvd

+0

@Kasramvd quanto più grande hai provato? – Falmarri

risposta

12

creazione di array NumPy è molto più lento rispetto alla creazione di liste:

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 

Ci possono anche costi fissi sostenuti da chiamate di funzione NumPy prima La carne del calcolo può essere eseguita da una veloce funzione C/Fortran sottostante. Ciò può includere la garanzia che gli input siano array NumPy,

Questi costi di installazione/fissi sono qualcosa da tenere a mente prima di assumere che le soluzioni di NumPy sono intrinsecamente più veloci delle soluzioni di puro Python. NumPy brilla quando si imposta grandi array volta e quindi eseguire molti operazioni veloci NumPy sugli array. Potrebbe non riuscire a superare la pura Python se gli array sono piccoli perché il costo di installazione può superare il vantaggio di scaricare i calcoli in funzioni C/Fortran compilate. Per i piccoli array potrebbero semplicemente non essere sufficienti i calcoli per renderlo valevole.


Se si aumenta la dimensione degli array un po ', e spostare la creazione degli array nel setup, quindi NumPy può essere molto più veloce di puro 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')) 

rendimenti

s1: 4.6990 
s2: 0.1224 
s3: 0.1234 
+0

Quindi, il problema è che qui il test includeva la creazione delle strutture di dati e, con quello rimosso, 'numpy' sarebbe effettivamente più veloce? – TigerhawkT3

+0

Sì, penso che questo sia il motivo, perché quando ho usato la matrice numpy nella comprensione delle liste, questo approccio diventa più lento! – Kasramvd

+0

Quale shell/interprete stai usando dove puoi fare '% timeit python_expression'? –