2010-10-08 3 views
13

Я пишу некоторые процедуры моделирования в NumPy, которым нужно произвольно выбирать ячейки из массива NumPy и выполнять некоторую обработку на них. Все ячейки должны быть выбраны без замены (как в случае, когда ячейка выбрана, она не может быть выбрана снова, но все ячейки должны быть выбраны до конца).Выбор ячеек случайным образом из массива NumPy - без замены

Я перехожу из IDL, где я могу найти хороший способ сделать это, но я полагаю, что NumPy имеет хороший способ сделать это тоже. Что ты предлагаешь?

Обновление: Я должен был сказать, что я пытаюсь сделать это на 2D-массивах и, следовательно, вернуть набор 2D-индексов.

ответ

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]] 
+0

Спасибо за ваш ответ. Похоже, я должен был упомянуть в своем вопросе, что это 2D-массив ... и я хотел бы получить индексы 2D-массива для каждой ячейки, случайным образом без замены. Есть ли способ сделать это легко? I – robintw

+2

@robintw - 'numpy.random.shuffle' должен отлично работать на n-мерных массивах. Если вам нужны указатели, вы можете попробовать создать массивы индексов строк и столбцов (посмотрите в 'meshgrid') и затем перетасовать их. –

+0

@robintw: 2D массивы тоже не проблема, вы можете просто «изменить форму»(), чтобы получить 2D вместо 1D :) – Wolph

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, если вам удобнее использовать этот набор инструментов.

+0

Что такое 'a' в первом примере? Кроме того, выражение 'a = a' оценивается как' True', которое не может быть тем, что вы намереваетесь из вызова numdy 'where' (' numpy.where' занимает массив в масках). Вы имели в виду что-то вроде 'x, y = np.where (data == data)'? – Hooked

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] 
1

Допустим, у вас есть массив точек размером 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-представление на массив и сэкономите себе некоторый перебор по индексу.

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 
1

люди используют numpy версию 1.7 или более поздняя версия также может использовать встроенную функцию numpy.random.choice

3

Все эти ответы казались немного запутанными для меня.

Я предполагаю, что у вас есть многомерный массив, из которого вы хотите создать исчерпывающий список индексов. Вы хотите, чтобы эти индексы перетасовывались, чтобы затем вы могли получить доступ к каждому из элементов массива в произвольном порядке.

Следующий код будет делать это в простой и прямой вперед образом:

#!/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 может стать довольно значительным. Поэтому было бы неплохо иметь генератор . К сожалению, я не могу придумать, как строить перетасованный итератор в одиночку.

Смежные вопросы