Numpy Delete for 2-dimensional array

Question:

I have an ndarray of shape (10, 3) and an index list of length 10:

import numpy as np
arr = np.arange(10* 3).reshape((10, 3))
idxs = np.array([0, 1, 1, 1, 2, 0, 2, 2, 1 , 0])

I want to use numpy delete (or a numpy function that is suited better for the task) to delete the values in arr as indicated by idxs for each row. So in the zeroth row of arr I want to delete the 0th entry, in the first the first, in the second the first, and so on.

I tried something like

np.delete(arr, idxs, axis=1)

but it won’t work. Then I tried building an index list like this:

idlist = [np.arange(len(idxs)), idxs]
np.delete(arr, idlist)

but this doesn’t give me the results I want either.

Asked By: Pickniclas

||

Answers:

Let’s try extracting the other items by masking, then reshape:

arr[np.arange(arr.shape[1]) != idxs[:,None]].reshape(len(arr),-1)
Answered By: Quang Hoang

@Quang’s answer is good, but may benefit from some explanation.


np.delete works with whole rows or columns, not selected elements from each.

In [30]: arr = np.arange(10* 3).reshape((10, 3))
    ...: idxs = np.array([0, 1, 1, 1, 2, 0, 2, 2, 1 , 0])

Selecting items from the array is easy:

In [31]: arr[np.arange(10), idxs]
Out[31]: array([ 0,  4,  7, 10, 14, 15, 20, 23, 25, 27])

Selecting everything but these, takes a bit more work. np.delete is complex general code that does different things depending on the delete specification. But one thing it can do is create a True mask, and set the delete items to False.

For your 2d case we can:

In [33]: mask = np.ones(arr.shape, bool)
In [34]: mask[np.arange(10), idxs] = False
In [35]: arr[mask]
Out[35]: 
array([ 1,  2,  3,  5,  6,  8,  9, 11, 12, 13, 16, 17, 18, 19, 21, 22, 24,
       26, 28, 29])

boolean indexing produces a flat array, so we need to reshape to get 2d:

In [36]: arr[mask].reshape(10,2)
Out[36]: 
array([[ 1,  2],
       [ 3,  5],
       [ 6,  8],
       [ 9, 11],
       [12, 13],
       [16, 17],
       [18, 19],
       [21, 22],
       [24, 26],
       [28, 29]])

The Quand’s answer creates the mask in another way:

In [37]: arr[np.arange(arr.shape[1]) != idxs[:,None]]
Out[37]: 
array([ 1,  2,  3,  5,  6,  8,  9, 11, 12, 13, 16, 17, 18, 19, 21, 22, 24,
       26, 28, 29])
Answered By: hpaulj

Thanks for your question and the answers from Quang, and hpaulj.
I just want to add a second senario, where one wants to do the deletion from the other axis.

The index now has only 3 elements because there are only 3 columns in arr, for example:

idxs2 = np.array([1,2,3])

To delete the elements of each column according to the index in idxs2, one can do this

arr.T[np.array(np.arange(arr.shape[0]) != idxs2[:,None])].reshape(len(idxs2),-1).T

And the result becomes:

array([[ 0,  1,  2],
       [ 6,  4,  5],
       [ 9, 10,  8],
       [12, 13, 14],
       [15, 16, 17],
       [18, 19, 20],
       [21, 22, 23],
       [24, 25, 26],
       [27, 28, 29]])
Answered By: user2165
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.