2013-06-27 3 views
3

Скажем, у меня есть 3D numpy.array, например. с размерами x y z, есть ли способ перебрать срезы вдоль определенной оси? Нечто подобное:итерация по срезам ndarray

for layer in data.slices(dim=2): 
    # do something with layer 

Редактировать: Для того, чтобы уточнить, пример является тусклым = 3 массива, т.е. форма = (len_x, len_y, len_z). Elazar и, что то же самое, решения kamjagin работают, но не являются общими - вам нужно построить [:, :, i] вручную, что означает, что вам нужно знать размеры, а код недостаточно общий для обработки массивов произвольных размеров. Вы можете заполнить отсутствующий размер, используя что-то вроде [..., :], но снова вам все равно придется построить это самостоятельно.

Извините, должно быть, было яснее, пример был слишком простым!

+1

ЗАКАНЧИВАТЬ HTTP : //stackoverflow.com/questions/1589706/iterating-over-arbitrary-dimension-of-numpy-array. Метод swapaxes является самым быстрым, но наименее понятным. Подход kamjagin может быть обобщен путем построения кортежа для перехода в скобки (например, 'data [кортеж (slice (None), slice (None), i)]' такой же, как 'data [:,:, i] '). – AFoglia

+0

@AFoglia Я не думаю, что тайминги по этому вопросу очень актуальны. Использование 'swapaxes' или' rollaxis' займет немного больше времени при настройке цикла, но фактические итерации будут быстрее, см. Тайминги, добавленные к моему ответу. В вашем очень маленьком примере настройка была доминирующей над фактической итерацией. Я не согласен с читабельностью, но я могу быть слишком привык к numpy, чтобы заметить это. – Jaime

+1

@AFoglia numpy имеет аккуратный трюк для создания среза (кортежей) отдельно от объекта, который они должны индексировать: 'numpy.s _ [:,:, i]' эквивалентно 'tuple (slice (None), slice (None), i). – JAB

ответ

5

Итерация по первому измерению очень проста, см. ниже. Для того, чтобы перебирать другие, ролл, что измерение передней и сделать то же самое:

>>> data = np.arange(24).reshape(2, 3, 4) 
>>> for dim_0_slice in data: # the first dimension is easy 
...  print dim_0_slice 
... 
[[ 0 1 2 3] 
[ 4 5 6 7] 
[ 8 9 10 11]] 
[[12 13 14 15] 
[16 17 18 19] 
[20 21 22 23]] 
>>> for dim_1_slice in np.rollaxis(data, 1): # for the others, roll it to the front 
...  print dim_1_slice 
... 
[[ 0 1 2 3] 
[12 13 14 15]] 
[[ 4 5 6 7] 
[16 17 18 19]] 
[[ 8 9 10 11] 
[20 21 22 23]] 
>>> for dim_2_slice in np.rollaxis(data, 2): 
...  print dim_2_slice 
... 
[[ 0 4 8] 
[12 16 20]] 
[[ 1 5 9] 
[13 17 21]] 
[[ 2 6 10] 
[14 18 22]] 
[[ 3 7 11] 
[15 19 23]] 

EDIT Некоторые тайминги, чтобы сравнить различные методы довольно большим массивам:

In [7]: a = np.arange(200*100*300).reshape(200, 100, 300) 

In [8]: %timeit for j in xrange(100): a[:, j] 
10000 loops, best of 3: 60.2 us per loop 

In [9]: %timeit for j in xrange(100): a[:, j, :] 
10000 loops, best of 3: 82.8 us per loop 

In [10]: %timeit for j in np.rollaxis(a, 1): j 
10000 loops, best of 3: 28.2 us per loop 

In [11]: %timeit for j in np.swapaxes(a, 0, 1): j 
10000 loops, best of 3: 26.7 us per loop 
+0

О, аккуратно, я не знал о 'rollaxis()'. – JAB

+0

То же самое здесь, очень приятно! – zeycus

0

что-то в этом роде?

>>> data = np.array([[1,2,3],[4,5,6],[7,8,9]]) 
>>> for layer in [data[:,i] for i in range(3)]: 
...  print layer 
... 
[1 4 7] 
[2 5 8] 
[3 6 9] 
0

Поправьте меня, если я ошибаюсь, но мне кажется, что ваш 3D массив буду выглядеть:

>>> my_array.shape 
    (3,N) 

где N является размер вашего массива. Так что если вы хотите перебрать в одном измерении, вы можете просто сделать:

>>> for item in my_array[1,:]: 

Это будет перебирать на втором измерении.

+0

ah извините, должно быть, было яснее - это массив dim = 3, т. Е. Shape = (nx, ny, nz) – lost

1

Это, вероятно, может быть решена более элегантно, чем это, но один из способов сделать это, если вы знаете заранее тусклый (например, 2) является:

for i in range(data.shape[dim]): 
    layer = data[:,:,i] 

или тусклый = 0

for i in range(data.shape[dim]): 
    layer = data[i,:,:] 

и т. д.

+0

+1 Это идея, но вам нужно будет динамически строить ваш индексный кортеж, например. 'idx = (slice (None),) * dim + (i,) + (slice (None),) * (2-dim)', а затем 'layer = data [idx]'. Это меньше хлопот, чтобы перевернуть измерение в заданное положение (первое из них наиболее удобно), а затем всегда иметь одно и то же итерационное оборудование, см. Мой ответ. – Jaime

+0

Ahh отлично. Определенно более элегантно с рулоном-решением. – kamjagin