36

Given a numpy 2d array (or a matrix), I would like to extract all the columns but the i-th.

E. g. from

1 2 3 4
2 4 6 8
3 6 9 12

I would like to have, e.g.

1 2 3
2 4 6
3 6 9

or

1 2 4
2 4 8
3 6 12

I cannot find a pythonic way to do this. I now that you can extract given columns by simply

a[:,n]

or

a[:,[n,n+1,n+5]]

But what about extracting all of them but one?

Ferdinando Randisi
  • 4,068
  • 6
  • 32
  • 43

4 Answers4

49

Since for the general case you are going to be returning a copy anyway, you may find yourself producing more readable code by using np.delete:

>>> a = np.arange(12).reshape(3, 4)
>>> np.delete(a, 2, axis=1)
array([[ 0,  1,  3],
       [ 4,  5,  7],
       [ 8,  9, 11]])
Jaime
  • 65,696
  • 17
  • 124
  • 159
33

Use a slice that excludes the last element.

In [19]: a[:,:-1]
Out[19]: 
array([[1, 2, 3],
       [2, 4, 6],
       [3, 6, 9]])

If you want something other than the last element I'd just build a list to select with.

In [20]: selector = [x for x in range(a.shape[1]) if x != 2]
In [21]: a[:, selector]
Out[21]: 
array([[ 1,  2,  4],
       [ 2,  4,  8],
       [ 3,  6, 12]])

http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html

chrisb
  • 49,833
  • 8
  • 70
  • 70
  • Nice, note that this method uses advanced integer slicing (selecting columns by their indicies), whereas the solution I posted uses advanced boolean slicing (selecting columns with a boolean mask). Both are good. – Peter Gibson Jun 04 '14 at 00:34
  • I'm trying to make it even simpler by using the selector range(a.shape[1]).remove(2) but this doesn't seem to work. Do you know why? – Ferdinando Randisi Jun 04 '14 at 19:19
  • @FerdinandoRandisi `.remove` doesn't return the array it modifies it in place, so the result of `range(a.shape[1]).remove(2)` is `None`. You could use `selector = range(a.shape[1]); selector.remove(2)` – Peter Gibson Jun 04 '14 at 23:35
11

Take a look at numpy's advanced slicing

>>> import numpy as np
>>> a = np.array([[1,2,3,4], [2,4,6,8], [3,6,9,12]])
>>> a[:,np.array([True, True, False, True])]
array([[ 1,  2,  4],
       [ 2,  4,  8],
       [ 3,  6, 12]])
Peter Gibson
  • 19,086
  • 7
  • 60
  • 64
0

The answers given already can easily be adapted to selecting all but a list of columns, but here are a couple of explicit examples:

In [1]: import numpy as np
In [2]: a = np.arange(12).reshape(3, 4)
In [3]: a
Out[3]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In [4]: drop_cols = [0, 3]

# option 1: delete the columns you don't want (like @Jaime)
# (this is really the most straightforward)

In [5]: np.delete(a, drop_cols, axis=1)
Out[5]:
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]])

# option 2: pass the indices of columns to keep (like @chrisb)

In [6]: a[:, [i for i in range(a.shape[1]) if i not in drop_cols]]
Out[6]:
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]])

# option 3: use an array of T/F for each col (like @Peter Gibson)

In [7]: a[:, [i not in drop_cols for i in range(a.shape[1])]]
Out[7]:
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]])
Nathan
  • 9,651
  • 4
  • 45
  • 65