Выберите клетки случайным образом из Numpy Array - без замены
Вопрос
Я пишу несколько процедуров моделирования в NUMPY, который должен случайным образом выбирать ячейки из Numpy Array и выполнять некоторую обработку на них. Все клетки должны быть выбраны без замены (как в, после того, как ячейка была выбрана, она не может быть выбрана снова, но все клетки должны быть выбраны к концу).
Я перехожу с IDL, где я могу найти хороший способ сделать это, но я предполагаю, что Numpy имеет хороший способ сделать это тоже. Что ты предлагаешь?
Обновлять: Я должен был заявить, что я пытаюсь сделать это на 2D-массивах, и поэтому получить набор из 2D-индексов.
Решение
Как насчет использования 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]]
Другие советы
Все эти ответы казались немного запутанными для меня.
Я предполагаю, что у вас есть многомерный массив, из которого вы хотите создать исчерпывающий список индексов. Вы хотели бы, чтобы эти индексы перетасовали, чтобы вы могли получить доступ к каждому из элементов массива в случайном порядке.
Следующий код сделает это простым и прямым способом:
#!/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
может стать довольно значительным. Поэтому было бы неплохо иметь генератор. Отказ К сожалению, я не могу думать о том, как построить перетасованный итератор.
Расширение приятного ответа от @Вольф
Для 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
ТОО, если вам удобнее с этим набором инструментов.
Использовать random.sample
Для генерирования INT в 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]
Допустим, у вас есть массив точек данных размером 8x3
data = np.arange(50,74).reshape(8,-1)
Если вы действительно хотите попробовать, как вы говорите, все индексы как 2D-пары, самый компактный способ сделать это, что я могу думать, это:
#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-массива просто для перемещения их, в этом случае можно еще более компактно. Просто сделайте 1D View на массив и сэкономьте себе какой-то индекс.
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
люди, использующие Numpy версии 1.7 или более поздней версии, могут также использовать встроенную функцию numpy.random.choice