noio
noio

Reputation: 5812

Numpy indexing using array

I'm trying to return a (square) section from an array, where the indices wrap around the edges. I need to juggle some indexing, but it works, however, I expect the last two lines of codes to have the same result, why don't they? How does numpy interpret the last line?

And as a bonus question: Am I being woefully inefficient with this approach? I'm using the product because I need to modulo the range so it wraps around, otherwise I'd use a[imin:imax, jmin:jmax, :], of course.

import numpy as np
from itertools import product

i = np.arange(-1, 2) % 3
j = np.arange(1, 4) % 3

a = np.random.randint(1,10,(3,3,2))

print a[i,j,:]
# Gives 3 entries [(i[0],j[0]), (i[1],j[1]), (i[2],j[2])]
# This is not what I want...

indices = list(product(i, j))
print indices

indices = zip(*indices)

print 'a[indices]\n', a[indices]
# This works, but when I'm explicit:
print 'a[indices, :]\n', a[indices, :]
# Huh?

Upvotes: 1

Views: 242

Answers (3)

seberg
seberg

Reputation: 8975

To give another method of advanced indexing which is better in my opinion then the product solution.

If you have for every dimension an integer array these are broadcasted together and the output is the same output as the broadcast shape (you will see what I mean)...

i, j = np.ix_(i,j) # this adds extra empty axes

print i,j 

print a[i,j]
# and now you will actually *not* be surprised:
print a[i,j,:]

Note that this is a 3x3x2 array, while you had a 9x2 array, but simple reshape will fix that and the 3x3x2 array is actually closer to what you want probably.

Actually the surprise is still hidden in a way, because in your examples a[indices] is the same as a[indices[0], indicies[1]] but a[indicies,:] is a[(indicies[0], indicies[1]),:] which is not a big surprise that it is different. Note that a[indicies[0], indicies[1],:] does give the same result.

Upvotes: 3

ecatmur
ecatmur

Reputation: 157344

The problem is that advanced indexing is triggered if:

the selection object, obj, is [...] a tuple with at least one sequence object or ndarray

The easiest fix in your case is to use repeated indexing:

a[i][:, j]

An alternative would be to use ndarray.take, which will perform the modulo operation for you if you specify mode='wrap':

a.take(np.arange(-1, 2), axis=0, mode='wrap').take(np.arange(1, 4), axis=1, mode='wrap')

Upvotes: 4

Nicolas Barbey
Nicolas Barbey

Reputation: 6797

See : http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#advanced-indexing

When you add :, you are mixing integer indexing and slicing. The rules are quite complicated and better explained than I could in the above link.

Upvotes: 1

Related Questions