用Scipy计算行方式点积两个矩阵的矢量化方式

Cup*_*tor 32 numpy vectorization scipy matrix-multiplication dot-product

我想尽可能快地计算相同维度的两个矩阵的行方点积.这就是我这样做的方式:

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
Run Code Online (Sandbox Code Playgroud)

当然输出是:

[ 26.  14.]
Run Code Online (Sandbox Code Playgroud)

War*_*ser 25

检查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])
Run Code Online (Sandbox Code Playgroud)

看起来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
Run Code Online (Sandbox Code Playgroud)

  • 我非常喜欢einsum,确实可以避免使用它。但是,如果主要考虑性能而不是代码样式,那么使用点和循环可能会更好(取决于您的特定数据和系统环境)。与einsum相比,dot可以利用BLAS的优势,并且通常会自动执行多线程。http://mail.scipy.org/pipermail/numpy-discussion/2012-October/064277.html (2认同)

sim*_*sim 24

直截了当的方法是:

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)
Run Code Online (Sandbox Code Playgroud)

这避免了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
Run Code Online (Sandbox Code Playgroud)


Nic*_*mer 22

玩弄这个,发现inner1d最快:

在此输入图像描述

该图是用perfplot(我的一个小项目)创建的

numpy.einsum("ij,ij->i", a, b)
Run Code Online (Sandbox Code Playgroud)


Pau*_*aul 5

你会更好地避免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
Run Code Online (Sandbox Code Playgroud)

编辑

根据这个答案inner1d如果您的实际问题中的向量是一维的,它看起来可能会起作用。

from numpy.core.umath_tests import inner1d
inner1d(a,b)  # array([14, 26])
Run Code Online (Sandbox Code Playgroud)