Equivalent of np.delete?

Hi,

I would like to do the same as:

import numpy as np

a = np.array([[[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]],[[13,14,15],[16,17,18]]], 
              [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]],[[13,14,15],[16,17,18]]],
              [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]],[[13,14,15],[16,17,18]]],
              [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]],[[13,14,15],[16,17,18]]]])

>>> a.shape
(4, 3, 2, 3)

new = np.delete(a, (0, 1), axis=3)

>>> new.shape
(4, 3, 2, 1)

Which gives:

array([[[[ 3],
         [ 6]],

        [[ 9],
         [12]],

        [[15],
         [18]]],


       [[[ 3],
         [ 6]],

        [[ 9],
         [12]],

        [[15],
         [18]]],


       [[[ 3],
         [ 6]],

        [[ 9],
         [12]],

        [[15],
         [18]]],


       [[[ 3],
         [ 6]],

        [[ 9],
         [12]],

        [[15],
         [18]]]])

I think the closest analog is something like:

new = a[:, :, filter(!in((1,2)), 1:end)]

I think there was some discussion of an “inverse” slice that lets you say which indices to exclude, and maybe a package for it, but I can’t find it at the moment.

There is InvertedIndices.jl, which combined with selectdim might be the closest translation:

julia> using InvertedIndices: Not

julia> A = rand(Int8,4,5,3)
4×5×3 Array{Int8, 3}:
[:, :, 1] =
 -16   -71    64  -56   10
  42  -116  -111  106  -52
 -82     5    75  -75  -65
  89   -53    40   32  -74

[:, :, 2] =
   29   24   -77   21  -30
  -87  -38    64   40   51
   30  -84    44  -52  -29
 -118   55  -103   64  -97

[:, :, 3] =
 -109   52   32  100  -83
  -82   86  -24  117  121
  118   32  108   82   29
  124  106  -23  -87   62

julia> selectdim(A, 2, Not(2:4))
4×2×3 view(::Array{Int8, 3}, :, [1, 5], :) with eltype Int8:
[:, :, 1] =
 -16   10
  42  -52
 -82  -65
  89  -74

[:, :, 2] =
   29  -30
  -87   51
   30  -29
 -118  -97

[:, :, 3] =
 -109  -83
  -82  121
  118   29
  124   62

julia> ans == A[:, Not(2:4), :]
true
1 Like

InvertedIndices.jl seems to underperform here?
E.g:

using InvertedIndices: Not

A = rand(Int8,4,5,3)

B1 = A[:, ∉(2:4).(1:end), :];           # 54 ns (5 allocs: 192 bytes)
B2 = A[:, filter(!in(2:4), 1:end), :];  # 70 ns (6 allocs: 272 bytes)
B3 = selectdim(A, 2, Not(2:4));         # 324 ns (16 allos: 592 bytes)
B4 = A[:, Not(2:4), :];                 # 856 ns (38 allocs: 1.36 KiB)

If your goal is simply to trim some number of slices from one edge (as in the initial example where you trim 2 slices from the beginning), the above can be further simplified to
a[:, :, begin+2:end] with no need for filter or InvertedIndices.jl.

If you only want a single slice (for example, the last slice) from that dimension, you can write this as a[:, :, end:end]. If you’d prefer to drop that now-definitely-single dimension then a[:, :, end] will do that.

4 Likes

It’s a common issue with InvertedIndices unfortunately, they are often surprisingly slow.

For removing indices in a vector, Accessors.jl are convenient and performant:

new_v = @delete v[123:456]

I think this only supports vectors for now – not because of some fundamental issue, just not implemented.

Same situation as deleteat!(), which I think is more performant.

I think @delete should be the same performance as copy + deleteat!.