2013-03-25 24 views
14

できるだけ速く同じ次元の2つの行列の行ごとの内積を計算したい。これは私がそれをやっている方法です。Scipyで行ごとの積2つの行列を計算するベクトル化された方法

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 

そしてもちろん出力は次のようになります。

[ 26. 14.] 
+3

あなたが本当に望むPythonコード?あなたは 'a'の1行目と2行目の内積と' b'の1行目と2行目のドット積を取っています。 '。 – jorgeca

+0

とjorgecaが言っているように、forの索引付けは間違っています:ドット(a [0、:]、a [1 ,:])、ドット(b [0 ,:]、b [1、:] ])、http://stackoverflow.com/questions/1663807/how-can-iterator-through-two-lists-in-parallel-in-python – lib

+0

説明をありがとうが、私は本当に私が探していたつまり、同じインデックスを持つ2つの乗算行が書かれています。 – Cupitor

答えて

18

チェックアウトnumpy.einsum

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

einsumのように見えるが少し速く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

私はeinsumが大好きで、あなたはそれでループを避けることができることは事実です。しかし、パフォーマンスとコードスタイルではなく、あなたの主な関心事であるならば、ドットやループ(あなたの特定のデータやシステム環境に依存します)を使う方が良いかもしれません。 einsumとは対照的に、dotはBLASを利用することができ、多くの場合自動的にマルチスレッド化されます。 http://mail.scipy.org/pipermail/numpy-discussion/2012-October/064277.html – PiQuer

4

あなたはより良いappendを避けてやるが、私は方法を考えることはできませんPythonのループを避けるために。おそらくカスタムUfunc?私はnumpy.vectorizeがここであなたを助けるとは思わない。

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 

this answerに基づきEDIT

あなたの実世界の問題ではベクトルは1次元であればinner1dはうまくいくかもしれないように、それが見えます。別の方法について

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

簡単な方法は次のとおりです。

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) 

Pythonのループを回避し、より高速のようなケースではされています

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

これで遊んとinner1d最速のが見つかりました:

enter image description here

プロットがperfplot(小さなプロジェクトで作成されました私の)

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)' 
     ) 
関連する問題