13

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

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

更新:我应该说我正在尝试在 2D 数组上执行此操作,因此得到一组 2D 索引。

4

6 回答 6

20

使用原始数组numpy.random.shuffle或者numpy.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]]
于 2010-10-08T13:52:26.110 回答
5

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

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

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

#!/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可能会变得相当大。因此,最好有一个生成器。可悲的是,我想不出如何随便构建一个洗牌的迭代器。

于 2013-09-08T21:20:48.467 回答
2

扩展来自@ 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:如果您对这套工具更满意,您也可以通过生成随机排序的索引。

于 2010-10-08T15:17:51.523 回答
1

用于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]
于 2010-10-08T17:36:27.717 回答
1

假设您有一个大小为 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

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

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

这仍然会根据需要置换 2d“原始”数组。要看到这一点,请尝试:

 flat_data[12] = 1000000
 print data[4,0]
 #returns 1000000
于 2011-01-15T07:29:42.537 回答
1

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

于 2013-08-11T22:19:28.253 回答