0

我有一个数组A[i,j]myfunc最后一个索引包含将应用于每个函数i并产生输出的函数的各种输入值B[i]。但是,许多索引的值j不会Bmyfunc. 这可以通过使用条件索引(例如C = C[C>mythreshold]for 循环)相对容易地切出相关值来实现,如下面的 MWE 所示:

def myfunc(X):
    return np.square(X).sum()
A = np.floor(np.random.rand(3,4)*100)
mythreshold = 10
(N1, N2) = A.shape
B = np.zeros(N1)
for i in range(N1):
    C = A[i,:]
    C = C[C>mythreshold]
    B[i] = myfunc(C)

我不得不把它分解成 for 循环,这样我就可以在A不删除整个数组的切片的情况下删除切片。这是因为我不能删除A[i,:]for onei的元素而不删除另一个的相应元素i。但是,为了提高速度,我想尽可能地进行矢量化 - 以避免 for 循环并i一次性完成所有操作。我怎样才能做到这一点?

注意:那是 MWE;实际情况具有更大的数组维度,因此我的数组将是A[i,j,k,l]and B[i,j],因此 for 循环示例将类似于下面的代码。我认为额外的维度不会使事情复杂化,但值得一提以防万一。

(N1, N2, N3, N4) = A.shape
for i in range(N1):
    for j in range(N2):
        C = A[i,j,:,:].flatten()
        C = C[C>mythreshold]
        B[i,j] = myfunc(C)
4

1 回答 1

0
In [10]: A = np.floor(np.random.rand(3,4)*2*mythreshold)
In [11]: A
Out[11]: 
array([[14.,  4.,  1.,  8.],
       [11., 11.,  4.,  2.],
       [ 8.,  6., 18., 12.]])
In [12]: (N1, N2) = A.shape
    ...: B = np.zeros(N1)
    ...: for i in range(N1):
    ...:     C = A[i,:]
    ...:     C = C[C>mythreshold]
    ...:     B[i] = myfunc(C)
    ...: 
In [13]: B
Out[13]: array([196., 242., 468.])

整个数组的阈值测试:

In [14]: A>mythreshold
Out[14]: 
array([[ True, False, False, False],
       [ True,  True, False, False],
       [False, False,  True,  True]])

制作一个副本,并将其他值设置为 0(或无害的值):

In [15]: A1 = A.copy(); A1[A<=mythreshold]=0
In [16]: np.square(A1).sum(axis=1)
Out[16]: array([196., 242., 468.])

这并不能避免将函数应用于所有元素,但它避免了对行进行迭代。通常避免 python 级别循环会加快numpy代码速度。但是,如果您的函数不能像我对axis参数所做的那样“矢量化”,或者它是如此复杂以至于包含那些“0”值很昂贵,那么这不是要走的路。

如果你的函数包括ufunc,你可以使用它的where参数

In [17]: mask = A>mythreshold
In [18]: out = np.zeros_like(A)
In [19]: np.square(A, out=out, where=mask)
Out[19]: 
array([[196.,   0.,   0.,   0.],
       [121., 121.,   0.,   0.],
       [  0.,   0., 324., 144.]])
In [20]: _.sum(axis=1)
Out[20]: array([196., 242., 468.])

通常where在某些值给出不好的结果时使用,例如除以 0 或负数的对数。我不认为这可以节省时间,但还没有确定时间来确认这一点。

于 2021-02-17T00:26:22.357 回答