alice
alice

Reputation: 85

numpy assignment with masking

I am a newbie to Python. During an exercise I am supposed to use a mask to multiply all values below 100 in the following list by 2:

a = np.array([230, 10, 284, 39, 76])

So I wrote the following code:

import numpy as np
a = np.array([230, 10, 284, 39, 76])
cut = 100
a[a < cut] = a*2    

This results in the following error:
IndexError: index 230 is out of bounds for axis 0 with size 5

This is confusing since to my understanding, the a in [a < cut] actually refers to each value in array a, but the a in a*2 refers to the whole array.

How can I correct this code using the masking method, instead of using a loop?

Upvotes: 6

Views: 9593

Answers (4)

iGian
iGian

Reputation: 11193

Alternatively, once the mask is defined, you can use numpy.where or numpy.putmask

import numpy as np

a = np.array([230, 10, 284, 39, 76])
cut = 100
mask = a < cut # defines the mask

The first does't change the original array:

res = np.where(mask, a*2,a)
a #=> [230  10 284  39  76]
res #=> [230  20 284  78 152]

The second modifies the original array:

np.putmask(a, mask, a*2)
a #=> [230  20 284  78 152]

Upvotes: 3

hpaulj
hpaulj

Reputation: 231385

Your error looks like was produce by a[a] not a[a<cut]:

In [508]: a[a]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-508-bcb5f2cb8e92> in <module>()
----> 1 a[a]

IndexError: index 230 is out of bounds for axis 1 with size 5

But to look at the intended assignment:

In [497]: a = np.array([230, 10, 284, 39, 76])
In [498]: mask = a<100
In [499]: mask
Out[499]: array([False,  True, False,  True,  True])

So the mask selects 3 out of the 5 elements of a:

In [500]: a[mask]
Out[500]: array([10, 39, 76])

a*2 multiplies all elements of a, producing a 5 element array

In [501]: a*2
Out[501]: array([460,  20, 568,  78, 152])

matching the two is bound to get some sort of error; I get:

In [502]: a[mask] = a*2
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-502-3df3d7d2d307> in <module>()
----> 1 a[mask] = a*2

ValueError: NumPy boolean array indexing assignment cannot assign 5 input values to the 3 output values where the mask is true

But if I apply the mask on the right hand side as well:

In [503]: a[mask] = a[mask]*2
In [504]: a
Out[504]: array([230,  20, 284,  78, 152])

But *= makes the inplace multiplication even easier.

In [506]: a[mask] *= 2

Upvotes: 0

Kevin He
Kevin He

Reputation: 1250

Not exactly sure what you want, if you want to assign to places where a < cut holds (a < cut = [0, 1, 0, 1, 1] is the boolean index), when you assign to a[a < cut], you assign to the places where the element is 1, meaning on the right side it expects a numpy array of size 3 (or of course one number). You can do this

In [1]: a = np.array([230, 10, 284, 39, 76])

In [2]: a[a < cut] = 999

In [3]: a
Out[3]: array([230, 999, 284, 999, 999])

Or

In [1]: a = np.array([230, 10, 284, 39, 76])

In [2]: a[a < cut] = a[a < cut] * 2

In [3]: a
Out[3]: array([230,  20, 284,  78, 152])

To multiply the selected elements by 2.

Upvotes: 6

Szymon Maszke
Szymon Maszke

Reputation: 24701

Almost got it right;

a[a < cut] *= 2

It will perform the operation in-place, you are multiplying whole a array by two and trying to "fit it in" the a < cut space (not possible as numpy has array of fixed size after creating).

Upvotes: 2

Related Questions