【问题标题】:numpy bincount - choose the max weight instead of sum all weightsnumpy bincount - 选择最大权重而不是总和所有权重
【发布时间】:2017-11-28 07:04:28
【问题描述】:

是否可以使用np.bincount 但获得最大值而不是权重总和?这里,索引3 处的bbb 有两个值,11.155.5。我想要55.5,而不是66.6。我怀疑我选择使用其他功能,但不确定哪一个适合此目的。

bbb = np.array([ 3, 7, 11, 13, 3])
weight = np.array([ 11.1, 22.2, 33.3, 44.4, 55.5])
print np.bincount(bbb, weight, minlength=15)

OUT >> [  0.    0.    0.   66.6   0.    0.    0.   22.2   0.    0.    0.   33.3   0.   44.4   0. ]

请注意,实际上bbbweight 非常大(大约5e6 元素)。

【问题讨论】:

    标签: python python-2.7 numpy


    【解决方案1】:

    可能没有 Nils 的回答那么快,但 numpy_indexed 包(免责声明:我是它的作者)具有更灵活的语法来执行这些类型的操作:

    import numpy_indexed as npi
    unique_keys, maxima_per_key = npi.group_by(bbb).max(weight)
    

    【讨论】:

      【解决方案2】:

      方法#1:这是使用np.maximum.reduceat 获得分箱最大值的一种方法 -

      def binned_max(bbb, weight, minlength):
          sidx = bbb.argsort()
          weight_s = weight[sidx]
          bbb_s = bbb[sidx]
          cut_idx = np.flatnonzero(np.concatenate(([True], bbb_s[1:] != bbb_s[:-1])))
          bbb_unq = bbb_s[cut_idx]
          #Or bbb_unq, cut_idx = np.unique(bbb_s, return_index=1)
          max_val = np.maximum.reduceat(weight_s, cut_idx)
          out = np.zeros(minlength, dtype=weight.dtype)
          out[bbb_unq] = max_val
          return out
      

      示例运行 -

      In [36]: bbb = np.array([ 3, 7, 11, 13, 3])
          ...: weight = np.array([ 11.1, 22.2, 33.3, 44.4, 55.5])
      
      In [37]: binned_max(bbb, weight, minlength=15)
      Out[37]: 
      array([  0. ,   0. ,   0. ,  55.5,   0. ,   0. ,   0. ,  22.2,   0. ,
               0. ,   0. ,  33.3,   0. ,  44.4,   0. ])
      

      方法 #2: 我试图通过numba 查看/玩得开心来解决这个问题,它似乎非常有效。这是一种麻木的方式-

      from numba import njit 
      
      @njit
      def numba_func(out, bins, weight, minlength):
          l = len(bins)
          for i in range(l):
              if out[bins[i]] < weight[i]:
                  out[bins[i]] = weight[i]
          return out
      
      def maxat_numba(bins, weight, minlength):
          out = np.zeros(minlength, dtype=weight.dtype)
          out[bins] = weight.min()
          numba_func(out, bins, weight, minlength)
          return out
      

      运行时测试-

      带有np.maximum.at 的内置插件看起来很整洁,在大多数情况下都是首选,因此针对它测试建议的那个 -

      # @Nils Werner's soln with np.maximum.at
      def maxat_numpy(bins, weight, minlength):
          out = np.zeros(minlength)
          np.maximum.at(out, bins, weight)
          return out
      

      时间安排 -

      案例#1:

      In [155]: bbb = np.random.randint(1,1000, (10000))
      
      In [156]: weight = np.random.rand(*bbb.shape)
      
      In [157]: %timeit maxat_numpy(bbb, weight, minlength=bbb.max()+1)
      1000 loops, best of 3: 686 µs per loop
      
      In [158]: %timeit maxat_numba(bbb, weight, minlength=bbb.max()+1)
      10000 loops, best of 3: 60.6 µs per loop
      

      案例#2:

      In [159]: bbb = np.random.randint(1,10000, (1000000))
      
      In [160]: weight = np.random.rand(*bbb.shape)
      
      In [161]: %timeit maxat_numpy(bbb, weight, minlength=bbb.max()+1)
      10 loops, best of 3: 66 ms per loop
      
      In [162]: %timeit maxat_numba(bbb, weight, minlength=bbb.max()+1)
      100 loops, best of 3: 5.42 ms per loop
      

      【讨论】:

      • np.maximum.reduceat(weight_s, cut_idx) 在这里如何工作?对了,如果数组很大,argsort()会不会很慢?
      • @Jan numpy.ufunc.reduceat 上的链接文档应该有助于澄清。我们不能在没有sorting 的情况下使用这个reduceat,所以这是必需的。
      【解决方案3】:

      solution to your 2D question 也适用于一维情况,所以你可以使用np.maxmimum.at

      out = np.zeros(15)
      np.maximum.at(out, bbb, weight)
      # array([  0. ,   0. ,   0. ,  55.5,   0. ,   0. ,   0. ,  22.2,   0. ,
      #          0. ,   0. ,  33.3,   0. ,  44.4,   0. ])
      

      【讨论】:

      • 确实在更大的阵列上看起来更好。
      猜你喜欢
      • 2022-10-04
      • 2020-10-24
      • 2011-07-01
      • 1970-01-01
      • 2011-04-29
      • 2017-01-21
      • 1970-01-01
      • 2017-04-12
      • 1970-01-01
      相关资源
      最近更新 更多