【问题标题】:Numpy argmax - random tie breakingNumpy argmax - 随机打破平局
【发布时间】:2022-05-04 23:12:14
【问题描述】:

numpy.argmax 函数中,多个最大元素之间的平局是为了返回第一个元素。 是否有随机抽签的功能,以便所有最大数字都有相同的机会被选中?

以下是直接来自 numpy.argmax 文档的示例。

>>> b = np.arange(6)
>>> b[1] = 5
>>> b
array([0, 5, 2, 3, 4, 5])
>>> np.argmax(b) # Only the first occurrence is returned.
1

我正在寻找方法使列表中的第 1 个和第 5 个元素以相等的概率返回。

谢谢!

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    使用np.random.choice -

    np.random.choice(np.flatnonzero(b == b.max()))
    

    让我们验证一个包含三个最大候选者的数组 -

    In [298]: b
    Out[298]: array([0, 5, 2, 5, 4, 5])
    
    In [299]: c=[np.random.choice(np.flatnonzero(b == b.max())) for i in range(100000)]
    
    In [300]: np.bincount(c)
    Out[300]: array([    0, 33180,     0, 33611,     0, 33209])
    

    【讨论】:

    • 如果你有浮点数而不是整数,你可能想用np.isclose(b, b.max())替换b == b.max()
    • arr.max() 可以替换为 np.max(arr) 以明确涉及 numpy 数组
    • 慢了大约三倍!
    【解决方案2】:

    在多维数组的情况下,choice 将不起作用。

    另一种选择是

    def randargmax(b,**kw):
      """ a random tie-breaking argmax"""
      return np.argmax(np.random.random(b.shape) * (b==b.max()), **kw)
    

    如果由于某种原因生成随机浮点数比其他方法慢,random.random 可以替换为其他方法。

    【讨论】:

    • 慢了大约 18 倍!
    【解决方案3】:

    最简单的方法是

    np.random.choice(np.where(b == b.max())[0])
    

    【讨论】:

    • 请提供一些解释以及答案。
    【解决方案4】:

    由于接受的答案可能并不明显,因此它的工作原理如下:

    • b == b.max() 将返回一个布尔数组,其中项目的最大值为 true,其他项目的值为 false
    • flatnonzero() 将做两件事:忽略 false 值(非零部分)然后返回 true 值的索引。换句话说,您会得到一个数组,其中包含与最大值匹配的项目索引
    • 最后,从数组中选择一个随机索引

    【讨论】:

      【解决方案5】:

      除了@Manux 的回答,

      b.max() 更改为np.amax(b,**kw, keepdims=True) 可以让您沿轴进行操作。

      def randargmax(b,**kw):
          """ a random tie-breaking argmax"""
          return np.argmax(np.random.random(b.shape) * (b==b.max()), **kw)
      
      randargmax(b,axis=None) 
      

      【讨论】:

        【解决方案6】:

        这是@divakar@shyam-padia对两种主要解决方案的比较:

        方法(一)——使用np.where

        np.random.choice(np.where(b == b.max())[0])
        

        方法(2) - 使用np.flatnonzero

        np.random.choice(np.flatnonzero(b == b.max())
        

        代码

        这是我为比较而编写的代码:

        def method1(b, bmax,):
            return np.random.choice(np.where(b == bmax)[0])
        
        def method2(b, bmax):
            return np.random.choice(np.flatnonzero(b == bmax))
        
        def time_it(n):
            b = np.array([1.0, 2.0, 5.0, 5.0, 0.4, 0.1, 5.0, 0.3, 0.1])
            bmax = b.max()
        
            start = time.perf_counter()
            for i in range(n):
                method1(b, bmax)
            elapsed1 = time.perf_counter() - start
            start = time.perf_counter() 
            for i in range(n):
                method2(b, bmax)
            elapsed2 = time.perf_counter() - start
        
            print(f'method1 time: {elapsed1} - method2 time: {elapsed2}')
            return elapsed1, elapsed2
        

        结果

        下图显示了运行[100, 1000, 10000, 100000, 1000000] 迭代的每个方法的计算时间,其中 x 轴表示迭代次数,y 轴以秒为单位显示时间。可以看出,当迭代次数增加时,np.where 的性能优于np.flatnonzero。请注意,x 轴具有对数刻度。

        为了显示这两种方法在较低迭代中的比较情况,我们可以通过将 y 轴设为对数刻度来重新绘制先前的结果。我们可以看到np.where 总是比np.flatnonzero 好。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-03-04
          • 2021-08-04
          • 2019-01-25
          • 2011-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-28
          相关资源
          最近更新 更多