seguito @ajcr's great answer, ho voluto per determinare quale metodo è il più veloce, quindi ho usato timeit
:
import timeit
setup_code = """
import numpy as np
i,j,k = (300,200,400)
ind = np.ones((i,j,k)) #shape=(3L, 2L, 4L)
dist = np.random.rand(i,j) #shape=(3L, 2L)
"""
basic ="np.array([np.dot(dist[l],ind[l]) for l in xrange(dist.shape[0])])"
einsum = "np.einsum('ijk,ij->ik', ind, dist)"
tensor= "np.tensordot(ind, dist, axes=[1, 1])[0].T"
print "tensor - total time:", min(timeit.repeat(stmt=tensor,setup=setup_code,number=10,repeat=3))
print "basic - total time:", min(timeit.repeat(stmt=basic,setup=setup_code,number=10,repeat=3))
print "einsum - total time:", min(timeit.repeat(stmt=einsum,setup=setup_code,number=10,repeat=3))
I sorprendenti risultati sono stati:
tensor - total time: 6.59519493952
basic - total time: 0.159871203461
einsum - total time: 0.263569731028
Così, ovviamente, utilizzando tensordot è stato il modo sbagliato di fallo (per non parlare dello memory error
in esempi più grandi, proprio come ha affermato @ajcr).
Da questo esempio era piccolo, ho cambiato la dimensione matrici essere i,j,k = (3000,200,400)
, capovolto l'ordine solo per essere sicuri che non ha effetto e impostare un altro test con alto numero di ripetizioni:
print "einsum - total time:", min(timeit.repeat(stmt=einsum,setup=setup_code,number=50,repeat=3))
print "basic - total time:", min(timeit.repeat(stmt=basic,setup=setup_code,number=50,repeat=3))
I risultati erano coerenti con la prima esecuzione:
einsum - total time: 13.3184077671
basic - total time: 8.44810031351
Tuttavia, testando un altro tipo di crescita dimensionale - i,j,k = (30000,20,40)
ha portato i seguenti risultati:
einsum - total time: 0.325594117768
basic - total time: 0.926416766397
Vedere i commenti per le spiegazioni di questi risultati.
La morale è, quando si cerca la soluzione più veloce per un problema specifico, provare a generare dati che siano il più possibile simili ai dati originali, in termini di tipi e forme. Nel mio caso i
è molto più piccolo di j,k
e così sono rimasto con la versione brutta, che è anche la più veloce in questo caso.
great (EDIT: ho accettato la risposta di @ ajcr, ma per favore leggi anche la mia risposta.) Aiuterà gli altri .. –