I have an array of distances called dists. I want to select dists which are within a range.
dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]
However, this selects only for the condition
(np.where(dists <= r + dr))
If I do the commands sequentially by using a temporary variable it works fine. Why does the above code not work, and how do I get it to work?
The best way in your particular case would just be to change your two criteria to one criterion:
dists[abs(dists - r - dr/2.) <= dr/2.]
It only creates one boolean array, and in my opinion is easier to read because it says, is dist within a dr or r? (Though I'd redefine r to be the center of your region of interest instead of the beginning, so r = r + dr/2.) But that doesn't answer your question.
The answer to your question:
You don't actually need where if you're just trying to filter out the elements of dists that don't fit your criteria:
dists[(dists >= r) & (dists <= r+dr)]
Because the & will give you an elementwise and (the parentheses are necessary).
Or, if you do want to use where for some reason, you can do:
dists[(np.where((dists >= r) & (dists <= r + dr)))]
Why:
The reason it doesn't work is because np.where returns a list of indices, not a boolean array. You're trying to get and between two lists of numbers, which of course doesn't have the True/False values that you expect. If a and b are both True values, then a and b returns b. So saying something like [0,1,2] and [2,3,4] will just give you [2,3,4]. Here it is in action:
In [230]: dists = np.arange(0,10,.5)
In [231]: r = 5
In [232]: dr = 1
In [233]: np.where(dists >= r)
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)
In [234]: np.where(dists <= r+dr)
Out[234]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),)
In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
Out[235]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),)
What you were expecting to compare was simply the boolean array, for example
In [236]: dists >= r
Out[236]:
array([False, False, False, False, False, False, False, False, False,
False, True, True, True, True, True, True, True, True,
True, True], dtype=bool)
In [237]: dists <= r + dr
Out[237]:
array([ True, True, True, True, True, True, True, True, True,
True, True, True, True, False, False, False, False, False,
False, False], dtype=bool)
In [238]: (dists >= r) & (dists <= r + dr)
Out[238]:
array([False, False, False, False, False, False, False, False, False,
False, True, True, True, False, False, False, False, False,
False, False], dtype=bool)
Now you can call np.where on the combined boolean array:
In [239]: np.where((dists >= r) & (dists <= r + dr))
Out[239]: (array([10, 11, 12]),)
In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
Out[240]: array([ 5. , 5.5, 6. ])
Or simply index the original array with the boolean array using fancy indexing
In [241]: dists[(dists >= r) & (dists <= r + dr)]
Out[241]: array([ 5. , 5.5, 6. ])
The accepted answer explained the problem well enough. However, the more Numpythonic approach for applying multiple conditions is to use numpy logical functions. In this case, you can use np.logical_and:
np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))
One interesting thing to point here; the usual way of using OR and AND too will work in this case, but with a small change. Instead of "and" and instead of "or", rather use Ampersand(&) and Pipe Operator(|) and it will work.
When we use 'and':
ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) and (ar<6), 'yo', ar)
Output:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
When we use Ampersand(&):
ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) & (ar<6), 'yo', ar)
Output:
array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')
And this is same in the case when we are trying to apply multiple filters in case of pandas Dataframe. Now the reasoning behind this has to do something with Logical Operators and Bitwise Operators and for more understanding about same, I'd suggest to go through this answer or similar Q/A in stackoverflow.
UPDATE
A user asked, why is there a need for giving (ar>3) and (ar<6) inside the parenthesis. Well here's the thing. Before I start talking about what's happening here, one needs to know about Operator precedence in Python.
Similar to what BODMAS is about, python also gives precedence to what should be performed first. Items inside the parenthesis are performed first and then the bitwise operator comes to work. I'll show below what happens in both the cases when you do use and not use "(", ")".
Case1:
np.where( ar>3 & ar<6, 'yo', ar)
np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)
Since there are no brackets here, the bitwise operator(&) is getting confused here that what are you even asking it to get logical AND of, because in the operator precedence table if you see, & is given precedence over < or > operators. Here's the table from from lowest precedence to highest precedence.
It's not even performing the < and > operation and being asked to perform a logical AND operation. So that's why it gives that error.
One can check out the following link to learn more about: operator
precedence
Now to Case 2:
If you do use the bracket, you clearly see what happens.
np.where( (ar>3) & (ar<6), 'yo', ar)
np.where( (array([False, True, True, True, False, True, False, True])) & (array([ True, True, True, False, True, True, True, False])), 'yo', ar)
Two arrays of True and False. And you can easily perform logical AND operation on them. Which gives you:
np.where( array([False, True, True, False, False, True, False, False]), 'yo', ar)
And rest you know, np.where, for given cases, wherever True, assigns first value(i.e. here 'yo') and if False, the other(i.e. here, keeping the original).
That's all. I hope I explained the query well.
To get np.where() working with multiple conditions, just do the following:
np.where((condition 1) & (condition 2)) # for and
np.where((condition 1) | (condition 2)) # for or
I know this repeats some other answers, but I put this simple answer here for people still wondering, "Why am I getting that annoying error message about The truth value of an array with more than one element is ambiguous" who are confused by the very verbose and complex answers that are addressing the somewhat specialized nature of the original post.
Now, as to why numpy breaks when you use and instead of &, I will not try to answer that here. It just does :) See other answers here for explanation. It seems like something they should just fix instead of forcing it for consistency IMHO. Or at least they should make a better error message. :)
I like to use np.vectorize for such tasks. Consider the following:
>>> # function which returns True when constraints are satisfied.
>>> func = lambda d: d >= r and d<= (r+dr)
>>>
>>> # Apply constraints element-wise to the dists array.
>>> result = np.vectorize(func)(dists)
>>>
>>> result = np.where(result) # Get output.
You can also use np.argwhere instead of np.where for clear output.
This should work:
dists[((dists >= r) & (dists <= r+dr))]
Try:
import numpy as np
dist = np.array([1,2,3,4,5])
r = 2
dr = 3
np.where(np.logical_and(dist> r, dist<=r+dr))
Output: (array([2, 3, 4]),)
You can see Logic functions for more details.
Try:
np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0])
I have worked out this simple example
import numpy as np
ar = np.array([3,4,5,14,2,4,3,7])
print [X for X in list(ar) if (X >= 3 and X <= 6)]
>>>
[3, 4, 5, 4, 3]
Related
I have an array of distances called dists. I want to select dists which are within a range.
dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]
However, this selects only for the condition
(np.where(dists <= r + dr))
If I do the commands sequentially by using a temporary variable it works fine. Why does the above code not work, and how do I get it to work?
The best way in your particular case would just be to change your two criteria to one criterion:
dists[abs(dists - r - dr/2.) <= dr/2.]
It only creates one boolean array, and in my opinion is easier to read because it says, is dist within a dr or r? (Though I'd redefine r to be the center of your region of interest instead of the beginning, so r = r + dr/2.) But that doesn't answer your question.
The answer to your question:
You don't actually need where if you're just trying to filter out the elements of dists that don't fit your criteria:
dists[(dists >= r) & (dists <= r+dr)]
Because the & will give you an elementwise and (the parentheses are necessary).
Or, if you do want to use where for some reason, you can do:
dists[(np.where((dists >= r) & (dists <= r + dr)))]
Why:
The reason it doesn't work is because np.where returns a list of indices, not a boolean array. You're trying to get and between two lists of numbers, which of course doesn't have the True/False values that you expect. If a and b are both True values, then a and b returns b. So saying something like [0,1,2] and [2,3,4] will just give you [2,3,4]. Here it is in action:
In [230]: dists = np.arange(0,10,.5)
In [231]: r = 5
In [232]: dr = 1
In [233]: np.where(dists >= r)
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)
In [234]: np.where(dists <= r+dr)
Out[234]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),)
In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
Out[235]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),)
What you were expecting to compare was simply the boolean array, for example
In [236]: dists >= r
Out[236]:
array([False, False, False, False, False, False, False, False, False,
False, True, True, True, True, True, True, True, True,
True, True], dtype=bool)
In [237]: dists <= r + dr
Out[237]:
array([ True, True, True, True, True, True, True, True, True,
True, True, True, True, False, False, False, False, False,
False, False], dtype=bool)
In [238]: (dists >= r) & (dists <= r + dr)
Out[238]:
array([False, False, False, False, False, False, False, False, False,
False, True, True, True, False, False, False, False, False,
False, False], dtype=bool)
Now you can call np.where on the combined boolean array:
In [239]: np.where((dists >= r) & (dists <= r + dr))
Out[239]: (array([10, 11, 12]),)
In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
Out[240]: array([ 5. , 5.5, 6. ])
Or simply index the original array with the boolean array using fancy indexing
In [241]: dists[(dists >= r) & (dists <= r + dr)]
Out[241]: array([ 5. , 5.5, 6. ])
The accepted answer explained the problem well enough. However, the more Numpythonic approach for applying multiple conditions is to use numpy logical functions. In this case, you can use np.logical_and:
np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))
One interesting thing to point here; the usual way of using OR and AND too will work in this case, but with a small change. Instead of "and" and instead of "or", rather use Ampersand(&) and Pipe Operator(|) and it will work.
When we use 'and':
ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) and (ar<6), 'yo', ar)
Output:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
When we use Ampersand(&):
ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) & (ar<6), 'yo', ar)
Output:
array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')
And this is same in the case when we are trying to apply multiple filters in case of pandas Dataframe. Now the reasoning behind this has to do something with Logical Operators and Bitwise Operators and for more understanding about same, I'd suggest to go through this answer or similar Q/A in stackoverflow.
UPDATE
A user asked, why is there a need for giving (ar>3) and (ar<6) inside the parenthesis. Well here's the thing. Before I start talking about what's happening here, one needs to know about Operator precedence in Python.
Similar to what BODMAS is about, python also gives precedence to what should be performed first. Items inside the parenthesis are performed first and then the bitwise operator comes to work. I'll show below what happens in both the cases when you do use and not use "(", ")".
Case1:
np.where( ar>3 & ar<6, 'yo', ar)
np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)
Since there are no brackets here, the bitwise operator(&) is getting confused here that what are you even asking it to get logical AND of, because in the operator precedence table if you see, & is given precedence over < or > operators. Here's the table from from lowest precedence to highest precedence.
It's not even performing the < and > operation and being asked to perform a logical AND operation. So that's why it gives that error.
One can check out the following link to learn more about: operator
precedence
Now to Case 2:
If you do use the bracket, you clearly see what happens.
np.where( (ar>3) & (ar<6), 'yo', ar)
np.where( (array([False, True, True, True, False, True, False, True])) & (array([ True, True, True, False, True, True, True, False])), 'yo', ar)
Two arrays of True and False. And you can easily perform logical AND operation on them. Which gives you:
np.where( array([False, True, True, False, False, True, False, False]), 'yo', ar)
And rest you know, np.where, for given cases, wherever True, assigns first value(i.e. here 'yo') and if False, the other(i.e. here, keeping the original).
That's all. I hope I explained the query well.
To get np.where() working with multiple conditions, just do the following:
np.where((condition 1) & (condition 2)) # for and
np.where((condition 1) | (condition 2)) # for or
I know this repeats some other answers, but I put this simple answer here for people still wondering, "Why am I getting that annoying error message about The truth value of an array with more than one element is ambiguous" who are confused by the very verbose and complex answers that are addressing the somewhat specialized nature of the original post.
Now, as to why numpy breaks when you use and instead of &, I will not try to answer that here. It just does :) See other answers here for explanation. It seems like something they should just fix instead of forcing it for consistency IMHO. Or at least they should make a better error message. :)
I like to use np.vectorize for such tasks. Consider the following:
>>> # function which returns True when constraints are satisfied.
>>> func = lambda d: d >= r and d<= (r+dr)
>>>
>>> # Apply constraints element-wise to the dists array.
>>> result = np.vectorize(func)(dists)
>>>
>>> result = np.where(result) # Get output.
You can also use np.argwhere instead of np.where for clear output.
This should work:
dists[((dists >= r) & (dists <= r+dr))]
Try:
import numpy as np
dist = np.array([1,2,3,4,5])
r = 2
dr = 3
np.where(np.logical_and(dist> r, dist<=r+dr))
Output: (array([2, 3, 4]),)
You can see Logic functions for more details.
Try:
np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0])
I have worked out this simple example
import numpy as np
ar = np.array([3,4,5,14,2,4,3,7])
print [X for X in list(ar) if (X >= 3 and X <= 6)]
>>>
[3, 4, 5, 4, 3]
Let x be a NumPy array. The following:
(x > 1) and (x < 3)
Gives the error message:
ValueError: The truth value of an array with more than one element is
ambiguous. Use a.any() or a.all()
How do I fix this?
If a and b are Boolean NumPy arrays, the & operation returns the elementwise-and of them:
a & b
That returns a Boolean array. To reduce this to a single Boolean value, use either
(a & b).any()
or
(a & b).all()
Note: if a and b are non-Boolean arrays, consider (a - b).any() or (a - b).all() instead.
Rationale
The NumPy developers felt there was no one commonly understood way to evaluate an array in Boolean context: it could mean True if any element is True, or it could mean True if all elements are True, or True if the array has non-zero length, just to name three possibilities.
Since different users might have different needs and different assumptions, the
NumPy developers refused to guess and instead decided to raise a ValueError whenever one tries to evaluate an array in Boolean context. Applying and to two numpy arrays causes the two arrays to be evaluated in Boolean context (by calling __bool__ in Python3 or __nonzero__ in Python2).
I had the same problem (i.e. indexing with multi-conditions, here it's finding data in a certain date range). The (a-b).any() or (a-b).all() seem not working, at least for me.
Alternatively I found another solution which works perfectly for my desired functionality (The truth value of an array with more than one element is ambigous when trying to index an array).
Instead of using suggested code above, use:
numpy.logical_and(a, b)
The reason for the exception is that and implicitly calls bool. First on the left operand and (if the left operand is True) then on the right operand. So x and y is equivalent to bool(x) and bool(y).
However the bool on a numpy.ndarray (if it contains more than one element) will throw the exception you have seen:
>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
The bool() call is implicit in and, but also in if, while, or, so any of the following examples will also fail:
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> while arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr or arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
There are more functions and statements in Python that hide bool calls, for example 2 < x < 10 is just another way of writing 2 < x and x < 10. And the and will call bool: bool(2 < x) and bool(x < 10).
The element-wise equivalent for and would be the np.logical_and function, similarly you could use np.logical_or as equivalent for or.
For boolean arrays - and comparisons like <, <=, ==, !=, >= and > on NumPy arrays return boolean NumPy arrays - you can also use the element-wise bitwise functions (and operators): np.bitwise_and (& operator)
>>> np.logical_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> np.bitwise_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> (arr > 1) & (arr < 3)
array([False, True, False], dtype=bool)
and bitwise_or (| operator):
>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> (arr <= 1) | (arr >= 3)
array([ True, False, True], dtype=bool)
A complete list of logical and binary functions can be found in the NumPy documentation:
"Logic functions"
"Binary operations"
if you work with pandas what solved the issue for me was that i was trying to do calculations when I had NA values, the solution was to run:
df = df.dropna()
And after that the calculation that failed.
Taking up #ZF007's answer, this is not answering your question as a whole, but can be the solution for the same error. I post it here since I have not found a direct solution as an answer to this error message elsewhere on Stack Overflow.
The error, among others, appears when you check whether an array was empty or not.
if np.array([1,2]): print(1) --> ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
if np.array([1,2])[0]: print(1) --> no ValueError, but: if np.array([])[0]: print(1) --> IndexError: index 0 is out of bounds for axis 0 with size 0.
if np.array([1]): print(1) --> no ValueError, but again will not help at an array with many elements.
if np.array([]): print(1) --> DeprecationWarning: The truth value of an empty array is ambiguous. Returning False, but in future this will result in an error. Use 'array.size > 0' to check that an array is not empty.
if np.array([]).size is not None: print(1): Taking up a comment by this user, this does not work either. This is since no np.array can ever be the same object as None - that object is unique - and thus will always match is not None (i.e. never match is None) whether or not it's empty.
Doing so:
if np.array([]).size: print(1) solved the error.
This typed error-message also shows while an if-statement comparison is done where there is an array and for example a bool or int. See for example:
... code snippet ...
if dataset == bool:
....
... code snippet ...
This clause has dataset as array and bool is euhm the "open door"... True or False.
In case the function is wrapped within a try-statement you will receive with except Exception as error: the message without its error-type:
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Normally, when you compare two single digits the Python regular codes work correctly, but inside an array there are some digits (more than one number) that should be processed in parallel.
For example, let us assume the following:
a = np.array([1, 2, 3])
b = np.array([2, 3, 4])
And you want to check if b >= a: ?
Because, a and b are not single digits and you actually mean if every element of b is greater than the similar number in a, then you should use the following command:
if (b >= a).all():
print("b is greater than a!")
Cause
This error occurs any time that the code attempts to convert a Numpy array to boolean (i.e., to check its truth value, as described in the error message). For a given array a, this can occur:
Explicitly, by using bool(a).
Implicitly with boolean logical operators: a and a, a or a, not a.
Implicitly using the built-in any and all functions. (These can accept a single array, regardless of how many dimensions it has; but cannot accept a list, tuple, set etc. of arrays.)
Implicitly in an if statement, using if a:. While it's normally possible to use any Python object in an if statement, Numpy arrays deliberately break this feature, because it could easily be used to write incorrect code by mistake otherwise.
Numpy arrays and comparisons (==, !=, <, >, <=, >=)
Comparisons have a special meaning for Numpy arrays. We will consider the == operator here; the rest behave analogously. Suppose we have
import numpy as np
>>> a = np.arange(9)
>>> b = a % 3
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> b
array([0, 1, 2, 0, 1, 2, 0, 1, 2])
Then, a == b does not mean "give a True or False answer: is a equal to b?", like it would usually mean. Instead, it will compare the values element by element, and evaluate to an array of boolean results for those comparisons:
>>> a == b
array([ True, True, True, False, False, False, False, False, False])
In other words, it does the same kind of broadcasting that mathematical operators (like b = a % 3) do.
It does not make sense to use this result for an if statement, because it is not clear what to do: should we enter the if block, because some of the values matched? Or should we enter the else block, because some of the values didn't match? Here, Numpy applies an important principle from the Zen of Python: "In the face of ambiguity, refuse the temptation to guess."
Thus, Numpy will only allow the array to be converted to bool, if it contains exactly one element. (In some older versions, it will also convert to False for an empty array; but there are good logical reasons why this should also be treated as ambiguous.)
Similarly, comparing a == 4 will not check whether the array is equal to the integer (of course, no array can ever be equal to any integer). Instead, it will broadcast the comparison across the array, giving a similar array of results:
>>> a == 4
array([False, False, False, False, True, False, False, False, False])
Fixing expressions
If the code is explicitly converting to bool, choose between applying .any or .all to the result, as appropriate. As the names suggest, .any will collapse the array to a single boolean, indicating whether any value was truthy; .all will check whether all values were truthy.
>>> (a == 4).all() # `a == 4` contains some `False` values
False
>>> (a == 4).any() # and also some `True` values
True
>>> a.all() # We can check `a` directly as well: `0` is not truthy,
False
>>> a.any() # but other values in `a` are.
True
If the goal is to convert a to boolean element-wise, use a.astype(bool), or (only for numeric inputs) a != 0.
If the code is using boolean logic (and/or/not), use bitwise operators (&/|/~, respectively) instead:
>>> ((a % 2) != 0) & ((a % 3) != 0) # N.B. `&`, not `and`
array([False, True, False, False, False, True, False, True, False])
Note that bitwise operators also offer access to ^ for an exclusive-or of the boolean inputs; this is not supported by logical operators (there is no xor).
For a list (or other sequence) of arrays that need to be combined in the same way (i.e., what the built-ins all and any do), instead build the corresponding (N+1)-dimensional array, and use np.all or np.any along axis 0:
>>> a = np.arange(100) # a larger array for a more complex calculation
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> all(sieves) # won't work
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
>>> np.all(np.array(sieves), axis=0) # instead:
array([False, True, False, False, False, False, False, False, False,
False, False, True, False, True, False, False, False, True,
False, True, False, False, False, True, False, False, False,
False, False, True, False, True, False, False, False, False,
False, True, False, False, False, True, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, True, False, True, False,
False, False, False, False, True, False, False, False, True,
False, True, False, False, False, False, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, False, False, True, False,
False])
Fixing if statements
First, keep in mind that if the code has an if statement that uses a broken expression (like if (a % 3 == 0) or (a % 5 == 0):), then both things will need to be fixed.
Generally, an explicit conversion to bool (using .all() or .any() as above) will avoid an exception:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... print('there are fizzbuzz values')
...
there are fizzbuzz values
but it might not do what is wanted:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... a = -1
...
>>> a
-1
If the goal is to operate on each value where the condition is true, then the natural way to do that is to use the mask as a mask. For example, to assign a new value everywhere the condition is true, simply index into the original array with the computed mask, and assign:
>>> a = np.arange(20)
>>> a[(a % 3 == 0) | (a % 5 == 0)] = -1
>>> a
array([-1, 1, 2, -1, 4, -1, -1, 7, 8, -1, -1, 11, -1, 13, 14, -1, 16,
17, -1, 19])
This indexing technique is also useful for finding values that meet a condition. Building on the previous sieves example:
>>> a = np.arange(100)
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> a[np.all(np.array(sieves), axis=0)]
array([ 1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97])
(Exercise: study the code and understand why this result isn't quite a list of primes under 100; then fix it.)
Using Pandas
The Pandas library has Numpy as a dependency, and implements its DataFrame type on top of Numpy's array type. All the same reasoning applies, such that Pandas Series (and DataFrame) objects cannot be used as boolean: see Truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
The Pandas interface for working around the problem is a bit more complicated - and best understood by reading that Q&A. The question specifically covers Series, but the logic generally applies to DataFrames as well. If you need more specific guidance, though, see If condition with a dataframe.
For me, this error occurred on testing, code with error below:
pixels = []
self.pixels = numpy.arange(1, 10)
self.assertEqual(self.pixels, pixels)
This code returned:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Because i cannot assert with a list the object returned by method arrange of numpy.
Solution as transform the arrange object of numpy to list, my choice was using the method toList(), as following:
pixels = []
self.pixels = numpy.arange(1, 10).toList()
self.assertEqual(self.pixels, pixels)
Simplest answer is use "&" instead of "and".
>>> import numpy as np
>>> arr = np.array([1, 4, 2, 7, 5])
>>> arr[(arr > 3) and (arr < 6)] # this will fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr[(arr > 3) & (arr < 6)] # this will succeed
array([4, 5])
Let x be a NumPy array. The following:
(x > 1) and (x < 3)
Gives the error message:
ValueError: The truth value of an array with more than one element is
ambiguous. Use a.any() or a.all()
How do I fix this?
If a and b are Boolean NumPy arrays, the & operation returns the elementwise-and of them:
a & b
That returns a Boolean array. To reduce this to a single Boolean value, use either
(a & b).any()
or
(a & b).all()
Note: if a and b are non-Boolean arrays, consider (a - b).any() or (a - b).all() instead.
Rationale
The NumPy developers felt there was no one commonly understood way to evaluate an array in Boolean context: it could mean True if any element is True, or it could mean True if all elements are True, or True if the array has non-zero length, just to name three possibilities.
Since different users might have different needs and different assumptions, the
NumPy developers refused to guess and instead decided to raise a ValueError whenever one tries to evaluate an array in Boolean context. Applying and to two numpy arrays causes the two arrays to be evaluated in Boolean context (by calling __bool__ in Python3 or __nonzero__ in Python2).
I had the same problem (i.e. indexing with multi-conditions, here it's finding data in a certain date range). The (a-b).any() or (a-b).all() seem not working, at least for me.
Alternatively I found another solution which works perfectly for my desired functionality (The truth value of an array with more than one element is ambigous when trying to index an array).
Instead of using suggested code above, use:
numpy.logical_and(a, b)
The reason for the exception is that and implicitly calls bool. First on the left operand and (if the left operand is True) then on the right operand. So x and y is equivalent to bool(x) and bool(y).
However the bool on a numpy.ndarray (if it contains more than one element) will throw the exception you have seen:
>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
The bool() call is implicit in and, but also in if, while, or, so any of the following examples will also fail:
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> while arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr or arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
There are more functions and statements in Python that hide bool calls, for example 2 < x < 10 is just another way of writing 2 < x and x < 10. And the and will call bool: bool(2 < x) and bool(x < 10).
The element-wise equivalent for and would be the np.logical_and function, similarly you could use np.logical_or as equivalent for or.
For boolean arrays - and comparisons like <, <=, ==, !=, >= and > on NumPy arrays return boolean NumPy arrays - you can also use the element-wise bitwise functions (and operators): np.bitwise_and (& operator)
>>> np.logical_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> np.bitwise_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> (arr > 1) & (arr < 3)
array([False, True, False], dtype=bool)
and bitwise_or (| operator):
>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> (arr <= 1) | (arr >= 3)
array([ True, False, True], dtype=bool)
A complete list of logical and binary functions can be found in the NumPy documentation:
"Logic functions"
"Binary operations"
if you work with pandas what solved the issue for me was that i was trying to do calculations when I had NA values, the solution was to run:
df = df.dropna()
And after that the calculation that failed.
Taking up #ZF007's answer, this is not answering your question as a whole, but can be the solution for the same error. I post it here since I have not found a direct solution as an answer to this error message elsewhere on Stack Overflow.
The error, among others, appears when you check whether an array was empty or not.
if np.array([1,2]): print(1) --> ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
if np.array([1,2])[0]: print(1) --> no ValueError, but: if np.array([])[0]: print(1) --> IndexError: index 0 is out of bounds for axis 0 with size 0.
if np.array([1]): print(1) --> no ValueError, but again will not help at an array with many elements.
if np.array([]): print(1) --> DeprecationWarning: The truth value of an empty array is ambiguous. Returning False, but in future this will result in an error. Use 'array.size > 0' to check that an array is not empty.
if np.array([]).size is not None: print(1): Taking up a comment by this user, this does not work either. This is since no np.array can ever be the same object as None - that object is unique - and thus will always match is not None (i.e. never match is None) whether or not it's empty.
Doing so:
if np.array([]).size: print(1) solved the error.
This typed error-message also shows while an if-statement comparison is done where there is an array and for example a bool or int. See for example:
... code snippet ...
if dataset == bool:
....
... code snippet ...
This clause has dataset as array and bool is euhm the "open door"... True or False.
In case the function is wrapped within a try-statement you will receive with except Exception as error: the message without its error-type:
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Normally, when you compare two single digits the Python regular codes work correctly, but inside an array there are some digits (more than one number) that should be processed in parallel.
For example, let us assume the following:
a = np.array([1, 2, 3])
b = np.array([2, 3, 4])
And you want to check if b >= a: ?
Because, a and b are not single digits and you actually mean if every element of b is greater than the similar number in a, then you should use the following command:
if (b >= a).all():
print("b is greater than a!")
Cause
This error occurs any time that the code attempts to convert a Numpy array to boolean (i.e., to check its truth value, as described in the error message). For a given array a, this can occur:
Explicitly, by using bool(a).
Implicitly with boolean logical operators: a and a, a or a, not a.
Implicitly using the built-in any and all functions. (These can accept a single array, regardless of how many dimensions it has; but cannot accept a list, tuple, set etc. of arrays.)
Implicitly in an if statement, using if a:. While it's normally possible to use any Python object in an if statement, Numpy arrays deliberately break this feature, because it could easily be used to write incorrect code by mistake otherwise.
Numpy arrays and comparisons (==, !=, <, >, <=, >=)
Comparisons have a special meaning for Numpy arrays. We will consider the == operator here; the rest behave analogously. Suppose we have
import numpy as np
>>> a = np.arange(9)
>>> b = a % 3
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> b
array([0, 1, 2, 0, 1, 2, 0, 1, 2])
Then, a == b does not mean "give a True or False answer: is a equal to b?", like it would usually mean. Instead, it will compare the values element by element, and evaluate to an array of boolean results for those comparisons:
>>> a == b
array([ True, True, True, False, False, False, False, False, False])
In other words, it does the same kind of broadcasting that mathematical operators (like b = a % 3) do.
It does not make sense to use this result for an if statement, because it is not clear what to do: should we enter the if block, because some of the values matched? Or should we enter the else block, because some of the values didn't match? Here, Numpy applies an important principle from the Zen of Python: "In the face of ambiguity, refuse the temptation to guess."
Thus, Numpy will only allow the array to be converted to bool, if it contains exactly one element. (In some older versions, it will also convert to False for an empty array; but there are good logical reasons why this should also be treated as ambiguous.)
Similarly, comparing a == 4 will not check whether the array is equal to the integer (of course, no array can ever be equal to any integer). Instead, it will broadcast the comparison across the array, giving a similar array of results:
>>> a == 4
array([False, False, False, False, True, False, False, False, False])
Fixing expressions
If the code is explicitly converting to bool, choose between applying .any or .all to the result, as appropriate. As the names suggest, .any will collapse the array to a single boolean, indicating whether any value was truthy; .all will check whether all values were truthy.
>>> (a == 4).all() # `a == 4` contains some `False` values
False
>>> (a == 4).any() # and also some `True` values
True
>>> a.all() # We can check `a` directly as well: `0` is not truthy,
False
>>> a.any() # but other values in `a` are.
True
If the goal is to convert a to boolean element-wise, use a.astype(bool), or (only for numeric inputs) a != 0.
If the code is using boolean logic (and/or/not), use bitwise operators (&/|/~, respectively) instead:
>>> ((a % 2) != 0) & ((a % 3) != 0) # N.B. `&`, not `and`
array([False, True, False, False, False, True, False, True, False])
Note that bitwise operators also offer access to ^ for an exclusive-or of the boolean inputs; this is not supported by logical operators (there is no xor).
For a list (or other sequence) of arrays that need to be combined in the same way (i.e., what the built-ins all and any do), instead build the corresponding (N+1)-dimensional array, and use np.all or np.any along axis 0:
>>> a = np.arange(100) # a larger array for a more complex calculation
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> all(sieves) # won't work
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
>>> np.all(np.array(sieves), axis=0) # instead:
array([False, True, False, False, False, False, False, False, False,
False, False, True, False, True, False, False, False, True,
False, True, False, False, False, True, False, False, False,
False, False, True, False, True, False, False, False, False,
False, True, False, False, False, True, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, True, False, True, False,
False, False, False, False, True, False, False, False, True,
False, True, False, False, False, False, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, False, False, True, False,
False])
Fixing if statements
First, keep in mind that if the code has an if statement that uses a broken expression (like if (a % 3 == 0) or (a % 5 == 0):), then both things will need to be fixed.
Generally, an explicit conversion to bool (using .all() or .any() as above) will avoid an exception:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... print('there are fizzbuzz values')
...
there are fizzbuzz values
but it might not do what is wanted:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... a = -1
...
>>> a
-1
If the goal is to operate on each value where the condition is true, then the natural way to do that is to use the mask as a mask. For example, to assign a new value everywhere the condition is true, simply index into the original array with the computed mask, and assign:
>>> a = np.arange(20)
>>> a[(a % 3 == 0) | (a % 5 == 0)] = -1
>>> a
array([-1, 1, 2, -1, 4, -1, -1, 7, 8, -1, -1, 11, -1, 13, 14, -1, 16,
17, -1, 19])
This indexing technique is also useful for finding values that meet a condition. Building on the previous sieves example:
>>> a = np.arange(100)
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> a[np.all(np.array(sieves), axis=0)]
array([ 1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97])
(Exercise: study the code and understand why this result isn't quite a list of primes under 100; then fix it.)
Using Pandas
The Pandas library has Numpy as a dependency, and implements its DataFrame type on top of Numpy's array type. All the same reasoning applies, such that Pandas Series (and DataFrame) objects cannot be used as boolean: see Truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
The Pandas interface for working around the problem is a bit more complicated - and best understood by reading that Q&A. The question specifically covers Series, but the logic generally applies to DataFrames as well. If you need more specific guidance, though, see If condition with a dataframe.
For me, this error occurred on testing, code with error below:
pixels = []
self.pixels = numpy.arange(1, 10)
self.assertEqual(self.pixels, pixels)
This code returned:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Because i cannot assert with a list the object returned by method arrange of numpy.
Solution as transform the arrange object of numpy to list, my choice was using the method toList(), as following:
pixels = []
self.pixels = numpy.arange(1, 10).toList()
self.assertEqual(self.pixels, pixels)
Simplest answer is use "&" instead of "and".
>>> import numpy as np
>>> arr = np.array([1, 4, 2, 7, 5])
>>> arr[(arr > 3) and (arr < 6)] # this will fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr[(arr > 3) & (arr < 6)] # this will succeed
array([4, 5])
What would be the way to select elements when two conditions are True in a matrix?
In R, it is basically possible to combine vectors of booleans.
So what I'm aiming for:
A = np.array([2,2,2,2,2])
A < 3 and A > 1 # A < 3 & A > 1 does not work either
Evals to:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
It should eval to:
array([True,True,True,True,True])
My workaround usually is to sum these boolean vectors and equate to 2, but there must be a better way. What is it?
you could just use &, eg:
x = np.arange(10)
(x<8) & (x>2)
gives
array([False, False, False, True, True, True, True, True, False, False], dtype=bool)
A few details:
This works because & is shorthand for the numpy ufunc bitwise_and, which for the bool type is the same as logical_and. That is, this could also be spelled out asbitwise_and(less(x,8), greater(x,2))
You need the parentheses because in numpy & has higher precedence than < and >
and does not work because it is ambiguous for numpy arrays, so rather than guess, numpy raise the exception.
There's a function for that:
In [8]: np.logical_and(A < 3, A > 1)
Out[8]: array([ True, True, True, True, True], dtype=bool)
Since you can't override the and operator in Python it always tries to cast its arguments to bool. That's why the code you have gives an error.
Numpy has defined the __and__ function for arrays which overrides the & operator. That's what the other answer is using.
While this is primitive, what is wrong with
A = [2, 2, 2, 2, 2]
b = []
for i in A:
b.append(A[i]>1 and A[i]<3)
print b
The output is [True, True, True, True, True]
Let x be a NumPy array. The following:
(x > 1) and (x < 3)
Gives the error message:
ValueError: The truth value of an array with more than one element is
ambiguous. Use a.any() or a.all()
How do I fix this?
If a and b are Boolean NumPy arrays, the & operation returns the elementwise-and of them:
a & b
That returns a Boolean array. To reduce this to a single Boolean value, use either
(a & b).any()
or
(a & b).all()
Note: if a and b are non-Boolean arrays, consider (a - b).any() or (a - b).all() instead.
Rationale
The NumPy developers felt there was no one commonly understood way to evaluate an array in Boolean context: it could mean True if any element is True, or it could mean True if all elements are True, or True if the array has non-zero length, just to name three possibilities.
Since different users might have different needs and different assumptions, the
NumPy developers refused to guess and instead decided to raise a ValueError whenever one tries to evaluate an array in Boolean context. Applying and to two numpy arrays causes the two arrays to be evaluated in Boolean context (by calling __bool__ in Python3 or __nonzero__ in Python2).
I had the same problem (i.e. indexing with multi-conditions, here it's finding data in a certain date range). The (a-b).any() or (a-b).all() seem not working, at least for me.
Alternatively I found another solution which works perfectly for my desired functionality (The truth value of an array with more than one element is ambigous when trying to index an array).
Instead of using suggested code above, use:
numpy.logical_and(a, b)
The reason for the exception is that and implicitly calls bool. First on the left operand and (if the left operand is True) then on the right operand. So x and y is equivalent to bool(x) and bool(y).
However the bool on a numpy.ndarray (if it contains more than one element) will throw the exception you have seen:
>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
The bool() call is implicit in and, but also in if, while, or, so any of the following examples will also fail:
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> while arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr or arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
There are more functions and statements in Python that hide bool calls, for example 2 < x < 10 is just another way of writing 2 < x and x < 10. And the and will call bool: bool(2 < x) and bool(x < 10).
The element-wise equivalent for and would be the np.logical_and function, similarly you could use np.logical_or as equivalent for or.
For boolean arrays - and comparisons like <, <=, ==, !=, >= and > on NumPy arrays return boolean NumPy arrays - you can also use the element-wise bitwise functions (and operators): np.bitwise_and (& operator)
>>> np.logical_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> np.bitwise_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> (arr > 1) & (arr < 3)
array([False, True, False], dtype=bool)
and bitwise_or (| operator):
>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> (arr <= 1) | (arr >= 3)
array([ True, False, True], dtype=bool)
A complete list of logical and binary functions can be found in the NumPy documentation:
"Logic functions"
"Binary operations"
if you work with pandas what solved the issue for me was that i was trying to do calculations when I had NA values, the solution was to run:
df = df.dropna()
And after that the calculation that failed.
Taking up #ZF007's answer, this is not answering your question as a whole, but can be the solution for the same error. I post it here since I have not found a direct solution as an answer to this error message elsewhere on Stack Overflow.
The error, among others, appears when you check whether an array was empty or not.
if np.array([1,2]): print(1) --> ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
if np.array([1,2])[0]: print(1) --> no ValueError, but: if np.array([])[0]: print(1) --> IndexError: index 0 is out of bounds for axis 0 with size 0.
if np.array([1]): print(1) --> no ValueError, but again will not help at an array with many elements.
if np.array([]): print(1) --> DeprecationWarning: The truth value of an empty array is ambiguous. Returning False, but in future this will result in an error. Use 'array.size > 0' to check that an array is not empty.
if np.array([]).size is not None: print(1): Taking up a comment by this user, this does not work either. This is since no np.array can ever be the same object as None - that object is unique - and thus will always match is not None (i.e. never match is None) whether or not it's empty.
Doing so:
if np.array([]).size: print(1) solved the error.
This typed error-message also shows while an if-statement comparison is done where there is an array and for example a bool or int. See for example:
... code snippet ...
if dataset == bool:
....
... code snippet ...
This clause has dataset as array and bool is euhm the "open door"... True or False.
In case the function is wrapped within a try-statement you will receive with except Exception as error: the message without its error-type:
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Normally, when you compare two single digits the Python regular codes work correctly, but inside an array there are some digits (more than one number) that should be processed in parallel.
For example, let us assume the following:
a = np.array([1, 2, 3])
b = np.array([2, 3, 4])
And you want to check if b >= a: ?
Because, a and b are not single digits and you actually mean if every element of b is greater than the similar number in a, then you should use the following command:
if (b >= a).all():
print("b is greater than a!")
Cause
This error occurs any time that the code attempts to convert a Numpy array to boolean (i.e., to check its truth value, as described in the error message). For a given array a, this can occur:
Explicitly, by using bool(a).
Implicitly with boolean logical operators: a and a, a or a, not a.
Implicitly using the built-in any and all functions. (These can accept a single array, regardless of how many dimensions it has; but cannot accept a list, tuple, set etc. of arrays.)
Implicitly in an if statement, using if a:. While it's normally possible to use any Python object in an if statement, Numpy arrays deliberately break this feature, because it could easily be used to write incorrect code by mistake otherwise.
Numpy arrays and comparisons (==, !=, <, >, <=, >=)
Comparisons have a special meaning for Numpy arrays. We will consider the == operator here; the rest behave analogously. Suppose we have
import numpy as np
>>> a = np.arange(9)
>>> b = a % 3
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> b
array([0, 1, 2, 0, 1, 2, 0, 1, 2])
Then, a == b does not mean "give a True or False answer: is a equal to b?", like it would usually mean. Instead, it will compare the values element by element, and evaluate to an array of boolean results for those comparisons:
>>> a == b
array([ True, True, True, False, False, False, False, False, False])
In other words, it does the same kind of broadcasting that mathematical operators (like b = a % 3) do.
It does not make sense to use this result for an if statement, because it is not clear what to do: should we enter the if block, because some of the values matched? Or should we enter the else block, because some of the values didn't match? Here, Numpy applies an important principle from the Zen of Python: "In the face of ambiguity, refuse the temptation to guess."
Thus, Numpy will only allow the array to be converted to bool, if it contains exactly one element. (In some older versions, it will also convert to False for an empty array; but there are good logical reasons why this should also be treated as ambiguous.)
Similarly, comparing a == 4 will not check whether the array is equal to the integer (of course, no array can ever be equal to any integer). Instead, it will broadcast the comparison across the array, giving a similar array of results:
>>> a == 4
array([False, False, False, False, True, False, False, False, False])
Fixing expressions
If the code is explicitly converting to bool, choose between applying .any or .all to the result, as appropriate. As the names suggest, .any will collapse the array to a single boolean, indicating whether any value was truthy; .all will check whether all values were truthy.
>>> (a == 4).all() # `a == 4` contains some `False` values
False
>>> (a == 4).any() # and also some `True` values
True
>>> a.all() # We can check `a` directly as well: `0` is not truthy,
False
>>> a.any() # but other values in `a` are.
True
If the goal is to convert a to boolean element-wise, use a.astype(bool), or (only for numeric inputs) a != 0.
If the code is using boolean logic (and/or/not), use bitwise operators (&/|/~, respectively) instead:
>>> ((a % 2) != 0) & ((a % 3) != 0) # N.B. `&`, not `and`
array([False, True, False, False, False, True, False, True, False])
Note that bitwise operators also offer access to ^ for an exclusive-or of the boolean inputs; this is not supported by logical operators (there is no xor).
For a list (or other sequence) of arrays that need to be combined in the same way (i.e., what the built-ins all and any do), instead build the corresponding (N+1)-dimensional array, and use np.all or np.any along axis 0:
>>> a = np.arange(100) # a larger array for a more complex calculation
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> all(sieves) # won't work
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
>>> np.all(np.array(sieves), axis=0) # instead:
array([False, True, False, False, False, False, False, False, False,
False, False, True, False, True, False, False, False, True,
False, True, False, False, False, True, False, False, False,
False, False, True, False, True, False, False, False, False,
False, True, False, False, False, True, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, True, False, True, False,
False, False, False, False, True, False, False, False, True,
False, True, False, False, False, False, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, False, False, True, False,
False])
Fixing if statements
First, keep in mind that if the code has an if statement that uses a broken expression (like if (a % 3 == 0) or (a % 5 == 0):), then both things will need to be fixed.
Generally, an explicit conversion to bool (using .all() or .any() as above) will avoid an exception:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... print('there are fizzbuzz values')
...
there are fizzbuzz values
but it might not do what is wanted:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... a = -1
...
>>> a
-1
If the goal is to operate on each value where the condition is true, then the natural way to do that is to use the mask as a mask. For example, to assign a new value everywhere the condition is true, simply index into the original array with the computed mask, and assign:
>>> a = np.arange(20)
>>> a[(a % 3 == 0) | (a % 5 == 0)] = -1
>>> a
array([-1, 1, 2, -1, 4, -1, -1, 7, 8, -1, -1, 11, -1, 13, 14, -1, 16,
17, -1, 19])
This indexing technique is also useful for finding values that meet a condition. Building on the previous sieves example:
>>> a = np.arange(100)
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> a[np.all(np.array(sieves), axis=0)]
array([ 1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97])
(Exercise: study the code and understand why this result isn't quite a list of primes under 100; then fix it.)
Using Pandas
The Pandas library has Numpy as a dependency, and implements its DataFrame type on top of Numpy's array type. All the same reasoning applies, such that Pandas Series (and DataFrame) objects cannot be used as boolean: see Truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
The Pandas interface for working around the problem is a bit more complicated - and best understood by reading that Q&A. The question specifically covers Series, but the logic generally applies to DataFrames as well. If you need more specific guidance, though, see If condition with a dataframe.
For me, this error occurred on testing, code with error below:
pixels = []
self.pixels = numpy.arange(1, 10)
self.assertEqual(self.pixels, pixels)
This code returned:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Because i cannot assert with a list the object returned by method arrange of numpy.
Solution as transform the arrange object of numpy to list, my choice was using the method toList(), as following:
pixels = []
self.pixels = numpy.arange(1, 10).toList()
self.assertEqual(self.pixels, pixels)
Simplest answer is use "&" instead of "and".
>>> import numpy as np
>>> arr = np.array([1, 4, 2, 7, 5])
>>> arr[(arr > 3) and (arr < 6)] # this will fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr[(arr > 3) & (arr < 6)] # this will succeed
array([4, 5])