【问题标题】:Numpy: argmax over multiple axes without loopNumpy:没有循环的多个轴上的argmax
【发布时间】:2015-08-15 20:09:44
【问题描述】:

我有一个 N 维数组(命名为 A)。对于A的第一轴的每一行,我想获得沿A的其他轴的最大值的坐标。然后我将返回一个二维数组,其中包含第一轴每一行的最大值的坐标A.

我已经使用循环解决了我的问题,但我想知道是否有更有效的方法来做到这一点。我目前的解决方案(以数组 A 为例)如下:

import numpy as np

A=np.reshape(np.concatenate((np.arange(0,12),np.arange(0,-4,-1))),(4,2,2))
maxpos=np.empty(shape=(4,2))
for n in range(0, 4):
    maxpos[n,:]=np.unravel_index(np.argmax(A[n,:,:]), A[n,:,:].shape)

在这里,我们会:

A: 
[[[ 0  1]
  [ 2  3]]

 [[ 4  5]
  [ 6  7]]

 [[ 8  9]
  [10 11]]

 [[ 0 -1]
  [-2 -3]]]

maxpos:
[[ 1.  1.]
 [ 1.  1.]
 [ 1.  1.]
 [ 0.  0.]]

如果有多个最大化器,我不介意选择哪个。

我尝试使用np.apply_over_axes,但我没有设法让它返回我想要的结果。

【问题讨论】:

    标签: python numpy vectorization argmax


    【解决方案1】:

    你可以这样做 -

    # Reshape input array to a 2D array with rows being kept as with original array.
    # Then, get idnices of max values along the columns.
    max_idx = A.reshape(A.shape[0],-1).argmax(1)
    
    # Get unravel indices corresponding to original shape of A
    maxpos_vect = np.column_stack(np.unravel_index(max_idx, A[0,:,:].shape))
    

    示例运行 -

    In [214]: # Input array
         ...: A = np.random.rand(5,4,3,7,8)
    
    In [215]: # Setup output array and use original loopy code
         ...: maxpos=np.empty(shape=(5,4)) # 4 because ndims in A is 5
         ...: for n in range(0, 5):
         ...:     maxpos[n,:]=np.unravel_index(np.argmax(A[n,:,:,:,:]), A[n,:,:,:,:].shape)
         ...:     
    
    In [216]: # Proposed approach
         ...: max_idx = A.reshape(A.shape[0],-1).argmax(1)
         ...: maxpos_vect = np.column_stack(np.unravel_index(max_idx, A[0,:,:].shape))
         ...: 
    
    In [219]: # Verify results
         ...: np.array_equal(maxpos.astype(int),maxpos_vect)
    Out[219]: True
    

    推广到n维数组

    我们可以概括求解 n-dim 数组以得到 argmax 的最后一个 N 轴与类似这样的组合 -

    def argmax_lastNaxes(A, N):
        s = A.shape
        new_shp = s[:-N] + (np.prod(s[-N:]),)
        max_idx = A.reshape(new_shp).argmax(-1)
        return np.unravel_index(max_idx, s[-N:])
    

    结果将是一个索引数组的元组。如果您需要最终输出为数组,我们可以使用np.stacknp.concatenate

    【讨论】:

    • 这个答案链接在stackoverflow.com/questions/62105979/…maxpos 是您的 OP 要求的,但它有什么用处?
    • @hpaulj 不确定“有用”是什么意思。 Maxpos 值是最后两个轴的 argmax 值,组合用于 3D 数组输入,索引回溯到最后两个轴的形状。这回答了你的问题了吗?或者您是在问这如何适用于 n-dim 数组?
    【解决方案2】:

    您可以使用列表推导

    result = [np.unravel_index(np.argmax(r), r.shape) for r in a]
    

    它的 IMO 更具可读性,但速度不会比显式循环好多少。

    只有在第一个维度实际上是非常大的维度时,主外部循环在 Python 中的事实才有意义。

    如果是这种情况(即您有一千万个 2x2 矩阵),那么翻转速度会更快...

    # true if 0,0 is not smaller than others
    m00 = ((data[:,0,0] >= data[:,1,0]) &
           (data[:,0,0] >= data[:,0,1]) &
           (data[:,0,0] >= data[:,1,1]))
    
    # true if 0,1 is not smaller than others
    m01 = ((data[:,0,1] >= data[:,1,0]) &
           (data[:,0,1] >= data[:,0,0]) &
           (data[:,0,1] >= data[:,1,1]))
    
    # true if 1,0 is not smaller than others
    m10 = ((data[:,1,0] >= data[:,0,0]) &
           (data[:,1,0] >= data[:,0,1]) &
           (data[:,1,0] >= data[:,1,1]))
    
    # true if 1,1 is not smaller than others
    m11 = ((data[:,1,1] >= data[:,1,0]) &
           (data[:,1,1] >= data[:,0,1]) &
           (data[:,1,1] >= data[:,0,0]))
    
    # choose which is max on equality
    m01 &= ~m00
    m10 &= ~(m00|m01)
    m11 &= ~(m00|m01|m10)
    
    # compute result
    result = np.zeros((len(data), 2), np.int32)
    result[:,1] |= m01|m11
    result[:,0] |= m10|m11
    

    在我的机器上,上面的代码大约快 50 倍(对于一百万个 2x2 矩阵)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-28
      • 2020-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-01
      • 2017-01-15
      相关资源
      最近更新 更多