I have an array and want ot extract all entries which are in a specific range
x = np.array([1,2,3,4])
condition = x<=4 and x>1
x_sel = np.extract(condition,x)
But this does not work. I'm getting
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
If I'm doing the same without the and and checking for example only one condition
x = np.array([1,2,3,4])
condition = x<=4
x_sel = np.extract(condition,x)
everything works...
Of courese I could just apply the procedure twice with one condition, but isn't there a solution to do this in one line?
Many thanks in advance
You can use either this:
import numpy as np
x = np.array([1,2,3,4])
condition = (x <= 4) & (x > 1)
x_sel = np.extract(condition,x)
print(x_sel)
# [2 3 4]
Or this without extract:
x_sel = x[(x > 1) & (x <= 4)]
This should work:
import numpy as np
x = np.array([1,2,3,4])
condition = (x<=4) & (x>1)
x_sel = np.extract(condition,x)
Mind the usage of and and &:
Difference between 'and' (boolean) vs. '&' (bitwise) in python. Why difference in behavior with lists vs numpy arrays?
Related
I have an array of numbers:
my_arr = np.array([n, n+1, n+2 ... , m-1, m]
I want to create an array of Booleans which indicate which numbers are in some (closed) interval, [A,B], to operate on some other related array that has the same shape. There are two cases:
Case 1: B >= m or A <= n
This case is trivial; the interval can be fully described with only one Boolean expression, and np.where() provides the solution to testing my array; e.g.:
my_boolean_arr = np.where(my_arr >= A)
or it's equivalent for B. This works.
Case 2: n <= A and m >= B
Here, I run into problems. I can no longer reduce my interval expression into a "single" Boolean expression. Python allows me to come close: the expression A < x < B will return a single (correct) Boolean. However,
my_boolean_arr = np.where(A <= my_arr <= B)
now fails:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
So, Two questions. First, how do I make this work? Second, why does this fail?
Operators "and" and "or" are not defined for numpy arrays.
In your case, you can use np.logical_and instead:
my_boolean_arr = np.logical_and(my_arr>=A, my_arr<=B)
https://numpy.org/doc/stable/reference/generated/numpy.logical_and.html
Alternative way is to use operator &
my_boolean_arr = (my_arr>=A) & (my_arr<=B)
possibly this has been asked before, but I have a hard time finding a corresponding solution, since I can't find the right keywords to search for it.
One huge advantage of numpy arrays that I like is that they are transparent for many operations.
However in my code I have a function that has a conditional statement in the form (minimal working example):
import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([1, 1, 3])
def func(x, y):
if x > y:
z = 1
else:
z = 2
return z
func(arr1, arr2) obviously results in an error message:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I do understand what the problem here is and why it can't work like this.
What I would like to do here is that x > y is evaluated for each element and then an array z is returned with the corresponding result for each comparison. (Needs to ensure of course that the arrays are of equal length, but that's not a problem here)
I know that I could do this by changing func such that it iterates over the elements, but since I'm trying to improve my numpy skills: is there a way to do this without explicit iteration?
arr1 > arr2 does exactly what you'd hope it does: compare each element of the two arrays and build an array with the result. The result can be used to index in any of the two arrays, should you need to. The equivalent of your function, however, can be done with np.where:
res = np.where(arr1 > arr2, 1, 2)
or equivalently (but slightly less efficiently), using the boolean array directly:
res = np.ones(arr1.shape)
res[arr1 <= arr2] = 2 # note that I have to invert the condition to select the cells where you want the 2
Suppose you have a ndarray z, and would like to get following indices
z_idxes1 = np.argwhere(z == i)
z_idxes2 = np.argwhere(z != i)
Can we do this in one call to some numpy function rather than two calls of argwhere?
Not in one call, but you can use logical not operator to get the negation of your mask array.
mask = (z == i)
z_idxes1 = np.argwhere(mask)
z_idxes2 = np.argwhere(~mask)
Simple question... I hope...
I've got a matrix, a , of size (n x m)
a = np.matrix([[1,2,3],[3,2,1],[6,4,1]])
and I'd like to extract a bool matrix, b, of size (n x m) for the following condition;
b = 3 < a > 7 and a != 6
However it is throwing the following error.
The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
Any help with this because I'm quite stuck.
Cheers!
You can't use and with arrays as you're trying to compare a single value with an array you have to use &, also you need to enclose the conditions in parentheses due to operator precedence:
In [56]:
a[(a > 3 ) & (a < 7) & (a != 6)]
Out[56]:
matrix([[4]])
what is the simplest way to get all rows where a complex condition holds for an ndarray that represents a 2d matrix? e.g. get all rows where all the values are above 5 or all the values are below 5?
thanks.
You probably know that boolean arrays can be used for indexing, e.g.:
import numpy as np
x = np.arange(10)
x2 = x[x<5]
For a boolean array, np.all lets you apply it across a given axis:
y = np.arange(12).reshape(3,4)
b = y < 6
b1 = np.all(b, axis=0)
b2 = np.all(b, axis=1)
y1 = y[b1]
y2 = y[b2]
It only returns the arrays which meet the criteria, so the shape is not preserved. (If you do need to preserve the shape, then take a look at masked arrays.)
This will give you the row indices of the rows where all values are lower or higher than 5:
x = numpy.arange(100).reshape(20,5)
numpy.where((x > 5).all(axis=1) ^ (x < 5).all(axis=1))
or more concisely (but not proceeding via the same logic):
numpy.where(((x > 5) ^ (x < 5)).all(axis=1))
To fetch the data, rather than the indices, use the boolean result directly:
x[((x > 5) ^ (x < 5)).all(axis=1)]