mindmatters
mindmatters

Reputation: 2515

Numpy index slice without losing dimension information

I'm using numpy and want to index a row without losing the dimension information.

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10,:]
xslice.shape   # >> (10,)  

In this example xslice is now 1 dimension, but I want it to be (1,10). In R, I would use X[10,:,drop=F]. Is there something similar in numpy. I couldn't find it in the documentation and didn't see a similar question asked.

Thanks!

Upvotes: 137

Views: 78421

Answers (7)

Saikiran Kannaiah
Saikiran Kannaiah

Reputation: 1

I've been using np.reshape to achieve the same as shown below

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10,:].reshape(1, -1)
xslice.shape   # >> (1, 10)  


Upvotes: 0

Joe Kington
Joe Kington

Reputation: 284850

It's probably easiest to do x[None, 10, :] or equivalently (but more readable) x[np.newaxis, 10, :]. None or np.newaxis increases the dimension of the array by 1, so that you're back to the original after the slicing eliminates a dimension.

As far as why it's not the default, personally, I find that constantly having arrays with singleton dimensions gets annoying very quickly. I'd guess the numpy devs felt the same way.

Also, numpy handle broadcasting arrays very well, so there's usually little reason to retain the dimension of the array the slice came from. If you did, then things like:

a = np.zeros((100,100,10))
b = np.zeros(100,10)
a[0,:,:] = b

either wouldn't work or would be much more difficult to implement.

(Or at least that's my guess at the numpy dev's reasoning behind dropping dimension info when slicing)

Upvotes: 73

Jthorpe
Jthorpe

Reputation: 10204

This is especially annoying if you're indexing by an array that might be length 1 at runtime. For that case, there's np.ix_:

some_array[np.ix_(row_index,column_index)]

Upvotes: 2

leilu
leilu

Reputation: 366

To add to the solution involving indexing by lists or arrays by gnebehay, it is also possible to use tuples:

X[(10,),:]

Upvotes: 5

Andrew Schwartz
Andrew Schwartz

Reputation: 4657

Here's an alternative I like better. Instead of indexing with a single number, index with a range. That is, use X[10:11,:]. (Note that 10:11 does not include 11).

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10:11,:]
xslice.shape   # >> (1,10)

This makes it easy to understand with more dimensions too, no None juggling and figuring out which axis to use which index. Also no need to do extra bookkeeping regarding array size, just i:i+1 for any i that you would have used in regular indexing.

b = np.ones((2, 3, 4))
b.shape # >> (2, 3, 4)
b[1:2,:,:].shape  # >> (1, 3, 4)
b[:, 2:3, :].shape .  # >> (2, 1, 4)

Upvotes: 21

gnebehay
gnebehay

Reputation: 1543

Another solution is to do

X[[10],:]

or

I = array([10])
X[I,:]

The dimensionality of an array is preserved when indexing is performed by a list (or an array) of indexes. This is nice because it leaves you with the choice between keeping the dimension and squeezing.

Upvotes: 127

mindmatters
mindmatters

Reputation: 2515

I found a few reasonable solutions.

1) use numpy.take(X,[10],0)

2) use this strange indexing X[10:11:, :]

Ideally, this should be the default. I never understood why dimensions are ever dropped. But that's a discussion for numpy...

Upvotes: 32

Related Questions