【问题标题】:Python - Randomly breaking ties when choosing a modePython - 选择模式时随机打破关系
【发布时间】:2020-07-08 16:10:09
【问题描述】:

scipy.stats.modeworks great,但我需要随机断开模态联系。

import numpy as np
import scipy.stats as stats

a = np.array([[3, 3, 4], 
              [3, 1, 0], 
              [4, 5, 0], 
              [4, 3, 0]])

stats.mode(a, axis=0)

Out[37]: ModeResult(mode=array([[3, 3, 0]]), count=array([[2, 2, 3]]))

对于第一个结果(列),scipy.stats.mode 在并列的候选 3 和 4 中选择 3,as follows

如果有多个这样的值,则只返回最小的。

所以在 3 和 4 中,它选择了 3,因为它是最小的。我想在 3 和 4 中随机选择,但 scipy.stats.mode 没有带回足够的信息让我这样做。有没有使用numpy 或不错的替代方法的好方法?

【问题讨论】:

    标签: python numpy scipy


    【解决方案1】:

    如果有人想出更好的方法,我仍然会回答,但这是我冗长的临时解决方案,它只是对 scipy.stats.mode 源代码的错误。唯一重要的修改是在for ind in inds 循环中,我使用np.where 带回所有具有相同最大计数的索引,并从中随机选择索引。

    from collections import namedtuple
    ModeResult = namedtuple('ModeResult', ('mode', 'count'))
    def mode_rand(a, axis):
        in_dims = list(range(a.ndim))
        a_view = np.transpose(a, in_dims[:axis] + in_dims[axis+1:] + [axis])
    
        inds = np.ndindex(a_view.shape[:-1])
        modes = np.empty(a_view.shape[:-1], dtype=a.dtype)
        counts = np.zeros(a_view.shape[:-1], dtype=np.int)
    
        for ind in inds:
            vals, cnts = np.unique(a_view[ind], return_counts=True)
            maxes = np.where(cnts == cnts.max())  # Here's the change
            modes[ind], counts[ind] = vals[np.random.choice(maxes[0])], cnts.max()
    
        newshape = list(a.shape)
        newshape[axis] = 1
        return ModeResult(modes.reshape(newshape), counts.reshape(newshape))
    
    mode_rand(a, axis=0)
    

    【讨论】:

      【解决方案2】:

      对于一种高效的方法,这里有一个numba 替代方案:

      from numba import njit, int32
      
      @njit
      def mode_rand_ties(a):
          out = np.zeros(a.shape[1], dtype=int32)
          for col in range(a.shape[1]):
              z = np.zeros(a[:,col].max()+1, dtype=int32)
              for v in a[:,col]:
                  z[v]+=1
              maxs = np.where(z == z.max())[0]
              out[col] = np.random.choice(maxs)
          return out
      

      在上面测试数组的地方,通过多次运行,我们可以看到我们可以得到34 作为第一列的模式:

      mode_rand_ties(a)
      # array([4, 3, 0], dtype=int32)
      
      mode_rand_ties(a)
      # array([3, 3, 0], dtype=int32)
      

      通过检查(4000, 3) 形状阵列的性能,我们发现它只需要大约 40us:

      x = np.concatenate([a]*1000, axis=0)
      %timeit mode_rand_ties(x)
      # 41.1 µs ± 13.2 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
      

      而目前的解决方案:

      %timeit mode_rand(x, axis=0)
      # 388 µs ± 23.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-06
        • 2011-01-01
        • 2014-04-23
        • 2019-05-05
        相关资源
        最近更新 更多