numpy在两个3d矩阵上应用函数

时间:2019-10-11 08:52:04

标签: python numpy

所以我想在numpy的两个3d矩阵上应用一个函数,但我不知道怎么做。我读到有关numpy.apply_over_axes()的信息,但无法使其正常工作。

现在这是我的代码:

c = np.random.beta(2,3,size=(2,80))

def my_func(a,b):
    xi = np.matmul(b, c)

    spe = np.power(a - xi, 2)
    return spe.sum()

a = np.zeros(shape=(5,1000,80))
b = np.random.beta(2,3,size=(5,1000,2))

np.apply_over_axes(func=my_func,a=[a,b],axes=[0,0,0])

不起作用并返回

could not broadcast input array from shape (5,1000,80) into shape (5,1000)

我想遍历ab并将my_func应用于第三维的每个向量。

这可以完成工作,但具有正常的for循环:

results = []
for i in range(len(a)): #5 Iterations
    for j in range(len(a[i])): #1000 Iterations
        results.append(my_func(a[i][j], b[i][j]))

我想获得这个results,但是要使用numpy函数。

2 个答案:

答案 0 :(得分:1)

隐藏在np.matmul(b, c)中的收缩操作可以通过np.tensordot(b, c, axes=[2, 0])来完成,其中[2, 0]表示b中的第三轴与{{ 1}}。也就是说,cnp.tensordot(b, c, axes=[2, 0]).shape。从那里开始,应用普通广播,您的代码归结为

(5, 1000, 80)

让我们检查一下它是否确实与您通过使用循环得到的结果相匹配:

a = np.zeros(shape=(5, 1000, 80))
b = np.random.beta(2, 3, size=(5, 1000, 2))
c = np.random.beta(2, 3, size=(2, 80))

xi = np.tensordot(b, c, axes=[2, 0])
spe = np.power(a - xi, 2)
results2 = spe.sum(axis=2)

答案 1 :(得分:-1)

ipython会话中运行代码:

In [88]: c = np.random.beta(2,3,size=(2,80)) 
    ...:  
    ...: def my_func(a,b): 
    ...:     xi = np.matmul(b, c) 
    ...:  
    ...:     spe = np.power(a - xi, 2) 
    ...:     return spe.sum() 
    ...:  
    ...: a = np.zeros(shape=(5,1000,80)) 
    ...: b = np.random.beta(2,3,size=(5,1000,2)) 
    ...:  
    ...: np.apply_over_axes(func=my_func,a=[a,b],axes=[0,0,0])                  
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-88-c5e5a66c9d0a> in <module>
     10 b = np.random.beta(2,3,size=(5,1000,2))
     11 
---> 12 np.apply_over_axes(func=my_func,a=[a,b],axes=[0,0,0])

<__array_function__ internals> in apply_over_axes(*args, **kwargs)

/usr/local/lib/python3.6/dist-packages/numpy/lib/shape_base.py in apply_over_axes(func, a, axes)
    485 
    486     """
--> 487     val = asarray(a)
    488     N = a.ndim
    489     if array(axes).ndim == 0:

/usr/local/lib/python3.6/dist-packages/numpy/core/_asarray.py in asarray(a, dtype, order)
     83 
     84     """
---> 85     return array(a, dtype, copy=False, order=order)
     86 
     87 

ValueError: could not broadcast input array from shape (5,1000,80) into shape (5,1000)

您应该向我们展示了完整的追溯错误。

该追溯表明我们正在尝试从两个列表中创建一个数组。由于形状不匹配,因此会引发错误。如果不匹配,则会创建一个(2,)对象数组,稍后它将移动引发问题:

In [89]: np.array([a,b])                                                        
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-89-964832cdcfcd> in <module>
----> 1 np.array([a,b])

ValueError: could not broadcast input array from shape (5,1000,80) into shape (5,1000)

但是问题是您没有阅读文档,或者没有认真对待它们:

func : function
    This function must take two arguments, `func(a, axis)`.
a : array_like
    Input array.
axes : array_like
    Axes over which `func` is applied; the elements must be integers.

a应该是一个数组,而不是两个数组的列表。 func应该接受一个axis参数,而不是另一个数组。而且我不知道您打算如何使用[0,0,0]。对于3d数组,[0,1]可能适用,但不能重复0。

您的循环

numpy样式更好:

In [91]: results = [] 
    ...: for i in range(a.shape[0]): #5 Iterations 
    ...:     for j in range(a.shape[1]): #1000 Iterations 
    ...:         results.append(my_func(a[i,j], b[i,j])) 
    ...:                                                                        
In [92]: np.array(results).shape                                                
Out[92]: (5000,)

返工my_func

要做到这一点而无需循环,我们需要在my_func中使用全数组函数。没有numpy apply会编译python代码-为此,您必须查看numbacython

xi=np.matmul(b,c)b是(5,1000,2),c是(2,80)。 matmul很高兴将dot的最后一个轴与b的第二个到最后一个轴进行组合。

c

In [93]: xi = np.matmul(b,c) In [94]: xi.shape Out[94]: (5, 1000, 80) 匹配,所以

a

然后在最后一个轴上求和:

In [97]: spe = np.power(a-xi,2)                                                 
In [98]: spe.shape                                                              
Out[98]: (5, 1000, 80)

与您的循环匹配的

In [99]: res = spe.sum(axis=2)                                                  
In [100]: res.shape                                                             
Out[100]: (5, 1000)

除最后一个In [101]: np.allclose(res.ravel(), np.array(results)) Out[101]: True 外,您的sum与整个数组一起运行。

myfunc