【问题标题】:Select cells randomly from NumPy array - without replacement从 NumPy 数组中随机选择单元格 - 无需替换
【发布时间】:2010-10-08 13:48:25
【问题描述】:

我正在 NumPy 中编写一些建模例程,这些例程需要从 NumPy 数组中随机选择单元格并对它们进行一些处理。必须选择所有单元格而不进行替换(例如,一旦选择了一个单元格,就不能再次选择它,但必须在最后选择所有单元格)。

我正在从 IDL 过渡,在那里我可以找到一个很好的方法来做到这一点,但我认为 NumPy 也有一个很好的方法来做到这一点。你有什么建议?

更新:我应该声明我正在尝试在 2D 数组上执行此操作,因此会返回一组 2D 索引。

【问题讨论】:

    标签: python random numpy shuffle sampling


    【解决方案1】:

    如果您仍然需要原始数组,如何使用numpy.random.shufflenumpy.random.permutation

    如果您需要就地更改数组,则可以像这样创建索引数组:

    your_array = <some numpy array>
    index_array = numpy.arange(your_array.size)
    numpy.random.shuffle(index_array)
    
    print your_array[index_array[:10]]
    

    【讨论】:

    • 感谢您的回答。看起来我应该在我的问题中提到这是二维数组......我想为每个单元格随机获取二维数组索引,无需替换。有没有办法轻松做到这一点?我
    • @robintw - numpy.random.shuffle 应该在 n 维数组上完美运行。如果您想要索引,您可以尝试制作行和列索引数组(查看meshgrid),然后将它们改组。
    • @robintw: 2D 数组也没有问题,你可以简单地reshape() 得到 2D 而不是 1D :)
    【解决方案2】:

    所有这些答案对我来说似乎有点令人费解。

    我假设您有一个多维数组,您希望从中生成详尽的索引列表。您希望这些索引被打乱,这样您就可以以随机顺序访问每个数组元素。

    以下代码将以简单直接的方式执行此操作:

    #!/usr/bin/python
    import numpy as np
    
    #Define a two-dimensional array
    #Use any number of dimensions, and dimensions of any size
    d=numpy.zeros(30).reshape((5,6))
    
    #Get a list of indices for an array of this shape
    indices=list(np.ndindex(d.shape))
    
    #Shuffle the indices in-place
    np.random.shuffle(indices)
    
    #Access array elements using the indices to do cool stuff
    for i in indices:
      d[i]=5
    
    print d
    

    打印d 验证所有元素都已被访问。

    请注意,数组可以有任意数量的维度,并且维度可以是任意大小。

    这种方法的唯一缺点是如果d 很大,那么indices 可能会变得相当大。因此,最好有一个生成器。可悲的是,我想不出如何随便构建一个洗牌的迭代器。

    【讨论】:

      【解决方案3】:

      扩展来自@WoLpH的好答案

      对于 2D 数组,我认为这取决于您想要或需要了解的有关索引的内容。

      你可以这样做:

      data = np.arange(25).reshape((5,5))
      
      x, y  = np.where( a = a)
      idx = zip(x,y)
      np.random.shuffle(idx)
      

      data = np.arange(25).reshape((5,5))
      
      grid = np.indices(data.shape)
      idx = zip( grid[0].ravel(), grid[1].ravel() )
      np.random.shuffle(idx)
      

      然后,您可以使用列表 idx 根据需要迭代随机排序的 2D 数组索引,并从保持不变的 data 中获取该索引处的值。

      注意:您也可以通过itertools.product 生成随机排序的索引,以防您更熟悉这套工具。

      【讨论】:

      • 第一个示例中的a 是什么?此外,表达式 a=a 的计算结果为 True,这不是您从 numpy where 调用中想要的(numpy.where 接受一个掩码数组)。你的意思是像x,y = np.where(data == data)这样的东西吗?
      【解决方案4】:

      使用random.sample 生成 0 .. A.size 的整数,没有重复, 然后将它们拆分为索引对:

      import random
      import numpy as np
      
      def randint2_nodup( nsample, A ):
          """ uniform int pairs, no dups:
              r = randint2_nodup( nsample, A )
              A[r]
              for jk in zip(*r):
                  ... A[jk]
          """
          assert A.ndim == 2
          sample = np.array( random.sample( xrange( A.size ), nsample ))  # nodup ints
          return sample // A.shape[1], sample % A.shape[1]  # pairs
      
      
      if __name__ == "__main__":
          import sys
      
          nsample = 8
          ncol = 5
          exec "\n".join( sys.argv[1:] )  # run this.py N= ...
          A = np.arange( 0, 2*ncol ).reshape((2,ncol))
      
          r = randint2_nodup( nsample, A )
          print "r:", r
          print "A[r]:", A[r]
          for jk in zip(*r):
              print jk, A[jk]
      

      【讨论】:

        【解决方案5】:

        假设您有一个大小为 8x3 的数据点数组

        data = np.arange(50,74).reshape(8,-1)
        

        如果你真的想像你说的那样对所有索引进行采样,那么我能想到的最紧凑的方法是:

        #generate a permutation of data's size, coerced to data's shape
        idxs = divmod(np.random.permutation(data.size),data.shape[1])
        
        #iterate over it
        for x,y in zip(*idxs): 
            #do something to data[x,y] here
            pass
        

        不过,通常情况下,人们通常不需要将二维数组作为二维数组来访问,以简单地对它们进行洗牌,在这种情况下,可以更紧凑。只需在数组上创建一个 1d 视图并为自己节省一些索引争论。

        flat_data = data.ravel()
        flat_idxs = np.random.permutation(flat_data.size)
        for i in flat_idxs:
            #do something to flat_data[i] here
            pass
        

        这仍然会根据您的需要置换二维“原始”数组。要查看此内容,请尝试:

         flat_data[12] = 1000000
         print data[4,0]
         #returns 1000000
        

        【讨论】:

          【解决方案6】:

          使用 numpy 1.7 或更高版本的人也可以使用内置函数numpy.random.choice

          【讨论】:

            猜你喜欢
            • 2017-09-16
            • 2015-10-02
            • 1970-01-01
            • 2014-06-20
            • 2018-08-05
            • 1970-01-01
            • 2014-05-15
            • 2017-09-16
            • 2021-12-14
            相关资源
            最近更新 更多