python - 有没有更快的方法来添加两个二维 numpy 数组

标签 python performance python-2.7 numpy optimization

假设我有两个相同尺寸的大型二维 numpy 数组(比如 2000x2000)。我想对它们进行元素明智的总结。我想知道是否有比 np.add() 更快的方法

编辑:我正在添加一个我现在使用的类似示例。有没有办法加快这个速度?

#a and b are the two matrices I already have.Dimension is 2000x2000
#shift is also a list that is previously known
for j in range(100000):
    b=np.roll(b, shift[j] , axis=0)
    a=np.add(a,b)

最佳答案

方法#1(矢量化)

我们可以使用 modulus模拟roll/circshift的循环行为并且使用广播索引来覆盖所有行,我们将有一个完全矢量化的方法,就像这样 -

n = b.shape[0]
idx = n-1 - np.mod(shift.cumsum()[:,None]-1 - np.arange(n), n)
a += b[idx].sum(0)

方法#2(循环一)
b_ext = np.row_stack((b, b[:-1] ))
start_idx = n-1 - np.mod(shift.cumsum()-1,n)
for j in range(start_idx.size):
    a += b_ext[start_idx[j]:start_idx[j]+n]

冒号符号与使用索引进行切片

一旦我们进入循环,这里的想法就是做最少的工作。我们在进入循环之前预先计算每次迭代的起始行索引。因此,我们在循环中需要做的就是使用冒号表示法进行切片,它是数组的 View 并相加。这应该比rolling好得多需要计算所有那些导致副本昂贵的行索引。

这里有更多关于使用冒号和索引切片时的 View 和复制概念 -
In [11]: a = np.random.randint(0,9,(10))

In [12]: a
Out[12]: array([8, 0, 1, 7, 5, 0, 6, 1, 7, 0])

In [13]: a[3:8]
Out[13]: array([7, 5, 0, 6, 1])

In [14]: a[[3,4,5,6,7]]
Out[14]: array([7, 5, 0, 6, 1])

In [15]: np.may_share_memory(a, a[3:8])
Out[15]: True

In [16]: np.may_share_memory(a, a[[3,4,5,6,7]])
Out[16]: False

运行时测试

功能定义 -
def original_loopy_app(a,b):
    for j in range(shift.size):
        b=np.roll(b, shift[j] , axis=0)
        a += b

def vectorized_app(a,b):
    n = b.shape[0]
    idx = n-1 - np.mod(shift.cumsum()[:,None]-1 - np.arange(n), n)
    a += b[idx].sum(0)

def modified_loopy_app(a,b):
    n = b.shape[0]
    b_ext = np.row_stack((b, b[:-1] ))
    start_idx = n-1 - np.mod(shift.cumsum()-1,n)
    for j in range(start_idx.size):
        a += b_ext[start_idx[j]:start_idx[j]+n]

情况1:
In [5]: # Setup input arrays
   ...: N = 200
   ...: M = 1000
   ...: a = np.random.randint(11,99,(N,N))
   ...: b = np.random.randint(11,99,(N,N))
   ...: shift = np.random.randint(0,N,M)
   ...: 

In [6]: original_loopy_app(a1,b1)
   ...: vectorized_app(a2,b2)
   ...: modified_loopy_app(a3,b3)
   ...: 

In [7]: np.allclose(a1, a2) # Verify results
Out[7]: True

In [8]: np.allclose(a1, a3) # Verify results
Out[8]: True

In [9]: %timeit original_loopy_app(a1,b1)
   ...: %timeit vectorized_app(a2,b2)
   ...: %timeit modified_loopy_app(a3,b3)
   ...: 
10 loops, best of 3: 107 ms per loop
10 loops, best of 3: 137 ms per loop
10 loops, best of 3: 48.2 ms per loop

案例#2:
In [13]: # Setup input arrays (datasets are exactly 1/10th of original sizes)
    ...: N = 200
    ...: M = 10000
    ...: a = np.random.randint(11,99,(N,N))
    ...: b = np.random.randint(11,99,(N,N))
    ...: shift = np.random.randint(0,N,M)
    ...: 

In [14]: %timeit original_loopy_app(a1,b1)
    ...: %timeit modified_loopy_app(a3,b3)
    ...: 
1 loops, best of 3: 1.11 s per loop
1 loops, best of 3: 481 ms per loop

所以,我们正在查看 2x+ 使用修改后的循环方法在那里加速!

关于python - 有没有更快的方法来添加两个二维 numpy 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41205764/

相关文章:

python - extend() 不生成列表

python - Django 1.9.2 断言错误 : database connection isn't set to UTC

Python,使用 Pyaudio 以 16000Hz 录制错误音频

c# - 哪个是最佳实践 : MethodReturnsBoolean == true/false OR true/false == MethodReturnsBoolean

python - 使用修饰函数作为函数的默认参数

python-2.7 - 保留 Datapath#ports 以保持兼容性

python - 使用正则表达式查找所有完全大写的短语

performance - 顶部的 "use ...."是否会增加 Perl 脚本的开销?

c# - 使用 Linq 搜索

Python mysql游标关闭连接