【问题标题】:cumulative argmax of a numpy arraynumpy 数组的累积 argmax
【发布时间】:2017-04-02 00:22:36
【问题描述】:

考虑数组a

np.random.seed([3,1415])
a = np.random.randint(0, 10, (10, 2))
a

array([[0, 2],
       [7, 3],
       [8, 7],
       [0, 6],
       [8, 6],
       [0, 2],
       [0, 4],
       [9, 7],
       [3, 2],
       [4, 3]])

什么是矢量化方法来获取累积的 argmax?

array([[0, 0],  <-- both start off as max position
       [1, 1],  <-- 7 > 0 so 1st col = 1, 3 > 2 2nd col = 1
       [2, 2],  <-- 8 > 7 1st col = 2, 7 > 3 2nd col = 2
       [2, 2],  <-- 0 < 8 1st col stays the same, 6 < 7 2nd col stays the same
       [2, 2],  
       [2, 2],
       [2, 2],
       [7, 2],  <-- 9 is new max of 2nd col, argmax is now 7
       [7, 2],
       [7, 2]])

这是一种非矢量化的方法。

请注意,随着窗口的扩展,argmax 适用于不断增长的窗口。

pd.DataFrame(a).expanding().apply(np.argmax).astype(int).values

array([[0, 0],
       [1, 1],
       [2, 2],
       [2, 2],
       [2, 2],
       [2, 2],
       [2, 2],
       [7, 2],
       [7, 2],
       [7, 2]])

【问题讨论】:

    标签: python arrays numpy vectorization argmax


    【解决方案1】:

    这是一个执行得非常快的矢量化纯 NumPy 解决方案:

    def cumargmax(a):
        m = np.maximum.accumulate(a)
        x = np.repeat(np.arange(a.shape[0])[:, None], a.shape[1], axis=1)
        x[1:] *= m[:-1] < m[1:]
        np.maximum.accumulate(x, axis=0, out=x)
        return x
    

    那么我们有:

    >>> cumargmax(a)
    array([[0, 0],
           [1, 1],
           [2, 2],
           [2, 2],
           [2, 2],
           [2, 2],
           [2, 2],
           [7, 2],
           [7, 2],
           [7, 2]])
    

    对具有数千到数百万个值的数组进行的一些快速测试表明,这比在 Python 级别(隐式或显式)循环快 10-50 倍。

    【讨论】:

    • 进一步优化 -- if a.ndim == 1: --> x = np.arange(a.shape[0])。只是因为 np.repeat 在这里(相对)是一个昂贵的电话。
    【解决方案2】:

    我想不出一种方法可以轻松地在两列上对其进行矢量化;但是如果列数相对于行数来说很小,那应该不是问题,for 循环对于该轴应该足够了:

    import numpy as np
    import numpy_indexed as npi
    a = np.random.randint(0, 10, (10))
    max = np.maximum.accumulate(a)
    idx = npi.indices(a, max)
    print(idx)
    

    【讨论】:

      【解决方案3】:

      我想创建一个函数来计算一维数组的累积 argmax,然后将其应用于所有列。这是代码:

      import numpy as np
      
      np.random.seed([3,1415])
      a = np.random.randint(0, 10, (10, 2))
      
      def cumargmax(v):
          uargmax = np.frompyfunc(lambda i, j: j if v[j] > v[i] else i, 2, 1)
          return uargmax.accumulate(np.arange(0, len(v)), 0, dtype=np.object).astype(v.dtype)
      
      np.apply_along_axis(cumargmax, 0, a)
      

      转换为np.object然后再转换回的原因是Numpy 1.9的一种解决方法,如generalized cumulative functions in NumPy/SciPy?中所述

      【讨论】:

      • 注意,frompyfunc 只对语法进行向量化;不是表现。这将具有与天真的 python 循环相当的性能。
      猜你喜欢
      • 2015-11-27
      • 1970-01-01
      • 1970-01-01
      • 2018-08-17
      • 2012-05-31
      • 1970-01-01
      • 1970-01-01
      • 2013-05-08
      • 2011-04-06
      相关资源
      最近更新 更多