20

I am trying to put all elements of rbs into a new array if the elements in var(another numpy array) is >=0 and <=.1 . However when I try the following code I get this error:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

rbs = [ish[4] for ish in realbooks]
for book in realbooks:
    var -= float(str(book[0]).replace(":", ""))
    bidsred = rbs[(var <= .1) and (var >=0)]

any ideas on what I'm doing wrong?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Rtrader
  • 917
  • 4
  • 11
  • 26
  • Which line causes the error? Also please format your code so it actually runs. – Brendan Long Sep 28 '12 at 21:18
  • It would help if you printed out the value of var. At a guess, the problem is in the string/float/text replaced variable you're decrementing... What does the original data look like that would require that series of operations? – abought Sep 28 '12 at 21:20
  • Aside from being a clear duplicate (the problem is caused by the `and` on the last line in the example, which is exactly the setup in the canonical), the title given here was misleading - the problem **did not** occur "when trying to index an array", but instead when trying to combine two masks with `and`. – Karl Knechtel Jan 03 '23 at 10:47

2 Answers2

35

The and keyword is used by Python to test between two booleans. How can an array be a boolean? If 75% of its items are True, is it True or False? Therefore, numpy refuses to compare the two.

Therefore, use either c[a & b] or c[np.logical_and(a, b)]. Either approach to combining the a and b arrays - a & b or np.logical_and(a, b) - will produce a boolean array with the same size as the input arrays a and b, which is necessary if the next step is to index into a same-sized array c.

A list of boolean values cannot be used for indexing instead. NumPy will interpret that as a list of index values (treating True as 1 and False as 0), so the output would contain multiple copies of the first two elements of the array, rather than a masked version.

Similarly, to choose elements from c where either of the corresponding elements from a or b is true, use c[a | b] or c[np.logical_or(a,b)].

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Pierre GM
  • 19,809
  • 3
  • 56
  • 67
13

This error message normally results from trying to use Python boolean operators (not, and, or) or comparison expressions involving Numpy arrays, e.g.:

>>> x = np.arange(-5, 5)
>>> (x > -2) and (x < 2)
Traceback (most recent call last):
  File "<ipython-input-6-475a0a26e11c>", line 1, in <module>
    (x > -2) and (x < 2)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

That's because such comparisons, unlike comparisons between built-in Python types, create arrays of booleans rather than single booleans:

>>> x > -2
array([False, False, False, False,  True,  True,  True,  True,  True,  True], dtype=bool)
>>> x < 2
array([ True,  True,  True,  True,  True,  True,  True, False, False, False], dtype=bool)

To fix this, replace the and operator with a call to np.logical_and, which broadcasts the AND operation over two arrays of np.bool.

>>> np.logical_and(x > -2, x < 2)
array([False, False, False, False,  True,  True,  True, False, False, False], dtype=bool)
>>> x[np.logical_and(x > -2, x < 2)]
array([-1,  0,  1])

However, such arrays of booleans cannot be used to index into ordinary Python lists, so the result of the list comprehension must be converted to an array first:

rbs = np.array([ish[4] for ish in realbooks])
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Fred Foo
  • 355,277
  • 75
  • 744
  • 836