成对的Numpy Apply函数成对出现并累积结果

时间:2019-04-20 16:39:20

标签: python function numpy list-comprehension

我想做些简单的事情,但还没有找到一种明智的方法。

假设我有一个numpy数组,其中包含3行,如下所示:

import numpy as np

a = np.array([[0.514, 0.966, 0.443, 0.95 , 0.524, 0.423, 0.75 , 0.463, 0.721, 0.089],
              [0.929, 0.014, 0.275, 0.521, 0.739, 0.612, 0.366, 0.469, 0.575, 0.533],
              [0.235, 0.084, 0.994, 0.713, 0.421, 0.851, 0.66 , 0.231, 0.699, 0.216]])

我想在每对行上应用以下函数 并累积结果 即(row0与row1)->(输出第3行的上一步),依此类推

def myfunc(x,y):
    return x**2 + y**2 - x*y

手动显示如下:

tmp1 = myfunc(a[0],a[1])
results = myfunc(tmp1,a[2])

现在,我想以一种聪明的方式将其概括为一般N (N = a.shape[0])

我已经尝试过基于列表理解的方法,但是无法将其推广到任何N。


编辑1:

N = 4的示例:

tmp1 = myfunc(a[0],a[1])
tmp2 = myfunc(tmp1,a[2])
results = myfunc(tmp2,a[3])

2 个答案:

答案 0 :(得分:1)

这是在第一个维度(即axis-0)上使用for循环解决此问题的一种简单方法:

# your custom function; slightly rewritten because
# * based multiplication is faster than `pow()`
In [93]: def myfunc(x,y):
    ...:     return x*x + y*y - x*y


# to be replenished after each iteration
In [95]: res = a[0]

# go over rows and compute the results using `myfunc()`
In [96]: for i in range(a.shape[0]-1):
    ...:    curr_step_res = myfunc(res, a[i+1])
    ...:    res = curr_step_res[:]


# final result
In [97]: res
Out[97]: 
array([0.32468859, 0.775874  , 0.861402  , 0.4852772 , 0.18264236,
       0.56028635, 0.33515591, 0.05036018, 0.37391415, 0.05364418])

手动调用的健全性检查

In [99]: tmp1 = myfunc(a[0],a[1])
In [100]: results = myfunc(tmp1,a[2])

In [101]: np.allclose(results, res)
Out[101]: True

您的案例的结果为N = 4

# sample array to work with
In [102]: a = np.random.random_sample((4, 6))

# to be replenished after each iteration
In [103]: res = a[0]

In [104]: for i in range(a.shape[0]-1):
     ...:    curr_step_res = myfunc(res, a[i+1])
     ...:    res = curr_step_res[:]

In [105]: res
Out[105]: 
array([0.51971283, 0.61377465, 0.0838452 , 0.2201938 , 0.54028219,
       0.19318569])

# compute using manual calls
In [106]: tmp1 = myfunc(a[0],a[1])
     ...: tmp2 = myfunc(tmp1,a[2])
     ...: results = myfunc(tmp2,a[3])

# sanity check for equality of both results
In [107]: np.allclose(results, res)
Out[107]: True

P.S。这应该推广到任何N,其中N = arr.shape[0]。另外,请注意,由于计算是顺序的,因此没有直接的方法可以并行化它。

答案 1 :(得分:1)

函数的简化版,以及应突出显示操作的a

In [344]: def myfunc(x,y): 
     ...:     return 2*x + y 
     ...: a = np.eye(5)                                                              
In [345]: a                                                                          
Out[345]: 
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])
In [346]: res = myfunc(a[0],a[1])                                                    
In [347]: res                                                                        
Out[347]: array([2., 1., 0., 0., 0.])
In [348]: for i in a[2:]: 
     ...:     res = myfunc(res,i) 
     ...:                                                                            
In [349]: res                                                                        
Out[349]: array([16.,  8.,  4.,  2.,  1.])

Python具有reduce函数,可将函数重复应用于列表。在Py3中,这是在functools中:

In [355]: functools.reduce(myfunc, a)                                                
Out[355]: array([16.,  8.,  4.,  2.,  1.])

或者以零res开头,然后应用于整个数组:

In [357]: res = np.zeros(a.shape[1])                                                 
In [358]: for i in a: 
     ...:     res = myfunc(res,i) 
     ...:                                                                            
In [359]: res                                                                        
Out[359]: array([16.,  8.,  4.,  2.,  1.])

要保存中间结果:

In [361]: res = [np.zeros(a.shape[1])] 
     ...: for i in a: 
     ...:     temp = myfunc(res[-1],i) 
     ...:     res.append(temp)                                                                            
In [362]: res                                                                        
Out[362]: 
[array([0., 0., 0., 0., 0.]),
 array([1., 0., 0., 0., 0.]),
 array([2., 1., 0., 0., 0.]),
 array([4., 2., 1., 0., 0.]),
 array([8., 4., 2., 1., 0.]),
 array([16.,  8.,  4.,  2.,  1.])]

这是accumulate的概念。 numpy ufunc同时具有reduceaccumulate,如果可以与myfunc一起写入,则速度会更快。但这在一般情况下不起作用。

In [363]: np.add.accumulate(a,axis=0)                                                
Out[363]: 
array([[1., 0., 0., 0., 0.],
       [1., 1., 0., 0., 0.],
       [1., 1., 1., 0., 0.],
       [1., 1., 1., 1., 0.],
       [1., 1., 1., 1., 1.]])