2014-07-19 69 views
4

给定一个4D数组M: (m, n, r, r),如何将所有m * n内部矩阵求和(形状为(r, r))以获得形状的新矩阵(r * r)Python - Sum 4D Array

例如,

M [[[[ 4, 1], 
     [ 2, 1]], 

     [[ 8, 2], 
     [ 4, 2]]], 

     [[[ 8, 2], 
     [ 4, 2]], 

     [[ 12, 3], 
     [ 6, 3]]]] 

我希望得到的结果应该是

 [[32, 8], 
     [16, 8]] 

回答

4

你可以使用einsum

In [21]: np.einsum('ijkl->kl', M) 
Out[21]: 
array([[32, 8], 
     [16, 8]]) 

其他选项包括重塑第一两个轴成一个轴,然后调用sum

In [24]: M.reshape(-1, 2, 2).sum(axis=0) 
Out[24]: 
array([[32, 8], 
     [16, 8]]) 

或调用的总和方法两次:

In [26]: M.sum(axis=0).sum(axis=0) 
Out[26]: 
array([[32, 8], 
     [16, 8]]) 

但是用np.einsum更快:

In [22]: %timeit np.einsum('ijkl->kl', M) 
100000 loops, best of 3: 2.42 µs per loop 

In [25]: %timeit M.reshape(-1, 2, 2).sum(axis=0) 
100000 loops, best of 3: 5.69 µs per loop 

In [43]: %timeit np.sum(M, axis=(0,1)) 
100000 loops, best of 3: 6.08 µs per loop 

In [33]: %timeit sum(sum(M)) 
100000 loops, best of 3: 8.18 µs per loop 

In [27]: %timeit M.sum(axis=0).sum(axis=0) 
100000 loops, best of 3: 9.83 µs per loop 

注意:由于许多因素(操作系统,NumPy版本,NumPy库,硬件等),timeit基准可能会有很大差异。各种方法的相对性能有时也取决于M的大小。因此,在M上进行自己的基准测试是值得的,它更接近您的实际使用情况。

例如,对于稍大阵列M,调用sum方法两次可以是最快的:

In [34]: M = np.random.random((100,100,2,2)) 

In [37]: %timeit M.sum(axis=0).sum(axis=0) 
10000 loops, best of 3: 59.9 µs per loop 

In [39]: %timeit np.einsum('ijkl->kl', M) 
10000 loops, best of 3: 99 µs per loop 

In [40]: %timeit np.sum(M, axis=(0,1)) 
10000 loops, best of 3: 182 µs per loop 

In [36]: %timeit M.reshape(-1, 2, 2).sum(axis=0) 
10000 loops, best of 3: 184 µs per loop 

In [38]: %timeit sum(sum(M)) 
1000 loops, best of 3: 202 µs per loop 
+0

与'sum(sum(M))'(由Cyber​​回答)相比,'np.einsum'更快吗? –

+0

我为'sum(sum(M))'添加了timeit基准。请注意,由于许多因素(OS,NumPy版本,NumPy库,硬件等),timeit基准测试可能会有很大差异。各种方法的相对性能有时也取决于'M'的大小。因此,在与您的实际使用情况更接近的'M'上执行您自己的基准测试是值得的。 – unutbu

+0

我怀疑这取决于M的大小(一些快速实验给出的结果违背了我的直觉,但是,我不能相信它们。) – DSM

1
import numpy as np 
l = np.array([[[[ 4, 1], 
       [ 2, 1]], 
       [[ 8, 2], 
       [ 4, 2]]], 
       [[[ 8, 2], 
       [ 4, 2]], 
       [[12, 3], 
       [ 6, 3]]]]) 
sum(sum(l)) 

输出

array([[32, 8], 
     [16, 8]]) 
3

到目前为止最简单的近numpy的(版本1.7或更高版本)是做:

np.sum(M, axis=(0, 1)) 

这不会构建一个中间数组,因为np.sum会重复调用。