Reputation: 85
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
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
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
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
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