35

I have a NumPy array like:

a = np.arange(30)

I know that I can replace the values located at positions indices=[2,3,4] using for instance fancy indexing:

a[indices] = 999

But how to replace the values at the positions that are not in indices? Would be something like below?

a[ not in indices ] = 888
Georgy
  • 12,464
  • 7
  • 65
  • 73
Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234

4 Answers4

50

I don't know of a clean way to do something like this:

mask = np.ones(a.shape,dtype=bool) #np.ones_like(a,dtype=bool)
mask[indices] = False
a[~mask] = 999
a[mask] = 888

Of course, if you prefer to use the numpy data-type, you could use dtype=np.bool_ -- There won't be any difference in the output. it's just a matter of preference really.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 4
    why not use `np.ones_like` – jamylak Jun 05 '13 at 13:27
  • @jamylak -- because I needed to look up the documentation on `np.ones_like`, but I knew how `np.ones` worked ;-) – mgilson Jun 05 '13 at 13:30
  • 4
    On a side note, you could replace your last couple of lines with a single call to `numpy.where` (this is the main case where it's really useful). E.g. `a = np.where(mask, 888, 999)`. – Joe Kington Jun 05 '13 at 13:32
  • 1
    @JoeKington -- Yep, that would be better for this case. (but it does allocate a new array) -- I just wanted to demonstrate that the mask variable can be negated using the `~` operator. – mgilson Jun 05 '13 at 13:34
  • @JoeKington true but the question doesn't ask for that – jamylak Jun 05 '13 at 13:35
  • 1
    @mgilson - Good point! It's something that a lot of folks don't know about, and your example illustrates it well. – Joe Kington Jun 05 '13 at 13:35
  • 3
    @JoeKington -- I suppose that `a[...] = np.where(mask,888,999)` would probably do the trick to overwrite `a` in place which demonstrates the Ellipsis operator that not many people know about :) – mgilson Jun 05 '13 at 13:36
  • 1
    @mgilson also better to use `np.bool_` – jamylak Jun 05 '13 at 13:38
  • 1
    @mgilson - True! `np.where` will still generate a temporary array for the assignment, though, so there's a difference in peak memory use from your original version. (Of course, `a` will still be modified in-place in the case of `a[...] = `, where it wasn't with `a = `.) – Joe Kington Jun 05 '13 at 13:40
  • 1
    @jamylak - There's no effective difference, and `np.bool_` often causes confusion. – Joe Kington Jun 05 '13 at 13:41
  • 1
    @JoeKington is it not recommended practice to use the numpy data types ? If you use `np.float16` for eg. may as well use `np.bool_` and so on – jamylak Jun 05 '13 at 13:44
  • 1
    @jamylak - It is, but passing in `bool` as the dtype just tells numpy to use a `np.bool_` dtype, so there's no difference in the output. The main reasons to use the numpy dtypes explicitly is to distinguish between different precisions (e.g. `np.float32` vs `float`/`np.float64` or `np.int8` vs `int`/`np.int64`). It's fine to be more explicit and use `np.float64`, but there's no good reason to use `np.bool_` over `bool`, as it's less clear what the result is for folks who aren't familiar with numpy. – Joe Kington Jun 05 '13 at 13:46
  • 1
    @JoeKington ok that makes sense, I didn't know it automatically switched to `bool_` – jamylak Jun 05 '13 at 13:51
  • 1
    @jamylak -- kind of like `float` automatically picks `np.float32` (which is a little strange since python floats correspond with `np.float64` I believe) – mgilson Jun 05 '13 at 13:51
6

Only works for 1d arrays:

a = np.arange(30)
indices = [2, 3, 4]

ia = np.indices(a.shape)

not_indices = np.setxor1d(ia, indices)
a[not_indices] = 888
aaren
  • 5,325
  • 6
  • 29
  • 24
4

Obviously there is no general not operator for sets. Your choices are:

  1. Subtracting your indices set from a universal set of indices (depends on the shape of a), but that will be a bit difficult to implement and read.
  2. Some kind of iteration (probably the for-loop is your best bet since you definitely want to use the fact that your indices are sorted).
  3. Creating a new array filled with new value, and selectively copying indices from the old one.

    b = np.repeat(888, a.shape)
    b[indices] = a[indices]
    
kirelagin
  • 13,248
  • 2
  • 42
  • 57
4

Just overcome similar situation, solved this way:

a = np.arange(30)
indices=[2,3,4]

a[indices] = 999

not_in_indices = [x for x in range(len(a)) if x not in indices]

a[not_in_indices] = 888
Alexey Trofimov
  • 4,287
  • 1
  • 18
  • 27