14

Desidero calcolare il prodotto punto-fila di due matrici della stessa dimensione il più velocemente possibile. Questo è il modo in cui lo faccio:Modo vettorizzato per calcolare le matrici di due punti del punto di riga con Scipy

import numpy as np 
a = np.array([[1,2,3], [3,4,5]]) 
b = np.array([[1,2,3], [1,2,3]]) 
result = np.array([]) 
for row1, row2 in a, b: 
    result = np.append(result, np.dot(row1, row2)) 
print result 

e, naturalmente, l'output è:

[ 26. 14.] 
+3

È il vostro Codice Python cosa vuoi veramente? Stai prendendo il prodotto punto della prima e seconda riga di 'a', e il prodotto punto della prima e seconda riga di' b', non il prodotto punto di ogni i-esima riga di 'a' e' b '. – jorgeca

+0

come ha detto jorgeca, l'indicizzazione è errata: in quel frammento di codice che stai facendo: punto (a [0,:], a [1 ,:]), punto (b [0 ,:], b [1 ,: ]), vedere http://stackoverflow.com/questions/1663807/how-can-i-iterate-through-two-lists-in-parallel-in-python – lib

+0

Grazie per la spiegazione, ma non stavo davvero cercando quello che ho ha scritto, cioè due file multiple con lo stesso indice. – Cupitor

risposta

18

Partenza numpy.einsum per un altro metodo:

In [52]: a 
Out[52]: 
array([[1, 2, 3], 
     [3, 4, 5]]) 

In [53]: b 
Out[53]: 
array([[1, 2, 3], 
     [1, 2, 3]]) 

In [54]: einsum('ij,ij->i', a, b) 
Out[54]: array([14, 26]) 

Sembra einsum è un po 'più veloce di inner1d:

In [94]: %timeit inner1d(a,b) 
1000000 loops, best of 3: 1.8 us per loop 

In [95]: %timeit einsum('ij,ij->i', a, b) 
1000000 loops, best of 3: 1.6 us per loop 

In [96]: a = random.randn(10, 100) 

In [97]: b = random.randn(10, 100) 

In [98]: %timeit inner1d(a,b) 
100000 loops, best of 3: 2.89 us per loop 

In [99]: %timeit einsum('ij,ij->i', a, b) 
100000 loops, best of 3: 2.03 us per loop 
+1

Mi piace molto einsum ed è vero che puoi evitare i loop con esso. Tuttavia, se le prestazioni e non lo stile del codice sono le tue preoccupazioni principali, potresti ancora stare meglio con il punto e il ciclo (a seconda dei dati specifici e dell'ambiente di sistema). A differenza di einsum, dot può sfruttare BLAS e spesso multithread automaticamente. http://mail.scipy.org/pipermail/numpy-discussion/2012-October/064277.html – PiQuer

4

Potrai fare meglio evitando la append, ma non riesco a pensare ad un modo per evitare il loop python. Forse un Ufunc personalizzato? Non credo che numpy.vectorize ti possa aiutare qui.

import numpy as np 
a=np.array([[1,2,3],[3,4,5]]) 
b=np.array([[1,2,3],[1,2,3]]) 
result=np.empty((2,)) 
for i in range(2): 
    result[i] = np.dot(a[i],b[i])) 
print result 

EDIT

Sulla base di this answer, sembra che inner1d potrebbe funzionare se i vettori nel tuo problema del mondo reale sono 1D.

from numpy.core.umath_tests import inner1d 
inner1d(a,b) # array([14, 26]) 
12

modo semplice per farlo è:

import numpy as np 
a=np.array([[1,2,3],[3,4,5]]) 
b=np.array([[1,2,3],[1,2,3]]) 
np.sum(a*b, axis=1) 

che evita il ciclo di pitone ed è più veloce in casi come:

def npsumdot(x, y): 
    return np.sum(x*y, axis=1) 

def loopdot(x, y): 
    result = np.empty((x.shape[0])) 
    for i in range(x.shape[0]): 
     result[i] = np.dot(x[i], y[i]) 
    return result 

timeit npsumdot(np.random.rand(500000,50),np.random.rand(500000,50)) 
# 1 loops, best of 3: 861 ms per loop 
timeit loopdot(np.random.rand(500000,50),np.random.rand(500000,50)) 
# 1 loops, best of 3: 1.58 s per loop 
8

giocato un po 'con questo e trovato inner1d il più veloce:

enter image description here

La trama è stato creato con perfplot (un piccolo progetto mio)

import numpy 
from numpy.core.umath_tests import inner1d 
import perfplot 

perfplot.show(
     setup=lambda n: (numpy.random.rand(n, 3), numpy.random.rand(n, 3)), 
     n_range=[2**k for k in range(1, 17)], 
     kernels=[ 
      lambda data: numpy.sum(data[0] * data[1], axis=1), 
      lambda data: numpy.einsum('ij, ij->i', data[0], data[1]), 
      lambda data: inner1d(data[0], data[1]) 
      ], 
     labels=['np.sum(a*b, axis=1)', 'einsum', 'inner1d'], 
     logx=True, 
     logy=True, 
     xlabel='len(a), len(b)' 
     )