-1
import numpy as np


a = np.array([[3.5,6,8,2]])
b = np.array([[6,2,8,2]])
c = np.array([[2,3,7,5]])
d = np.array([[3,2,5,1]])
if a > b:
    e = 2*a+6*c
else:
    e = 3*c + 4*d

print(e)

then I got

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

and if I type in print(e), I got

[2, 3, 7, 5, 2, 3, 7, 5, 2, 3, 7, 5, 3, 2, 5, 1, 3, 2, 5, 1, 3, 2, 5, 1, 3, 2, 5, 1]

The e I want to construct is an array that has the same dimension with a,b,c,d , and the if statement that decides what equation will be used to make each element.

In other words, for the elements in of the first place of a and b: 3.5<6, so e = 3c + 4d = 32 + 43 = 18 For the second elements: 6>2, e = 2a+6c = 26 + 63 = 30

Third: 8=8, e = 3c + 4d = 37 + 45 = 41

Fourth: 2 = 2, e = 3c + 4d = 35 + 41 = 19

e = [18,30,41,19]

I tried to find someone who asked about constructing a script doing such things, but I could find none, and all numpy questions about if statement(or equivalent) did not help. Thanks.(It seems that a.all or a.any from the python recommendation did not help as well.)

Brian Jan
  • 29
  • 3
  • Seems like a use case for [np.where()](https://numpy.org/doc/stable/reference/generated/numpy.where.html) – G. Anderson Jan 26 '22 at 22:10
  • `if` is a one time action, not a 'for each element' iterator. – hpaulj Jan 26 '22 at 22:57
  • @hpaulj many people who are new to Numpy get confused because Numpy data types cause a lot of operations to "broadcast", but there is nothing Numpy can do to make the *language syntax* also broadcast - so it creates awkward seams. `a * b` multiplies elementwise; `a == b` compares elementwise; but the result of that elementwise comparison can't be used to do conditional work elementwise. – Karl Knechtel Jul 22 '23 at 07:39
  • @KarlKnechtel, this is a clear cases where they want an element-wise application. In other cases it isn't so clear, even to the poster. The `all/any` suggestion isn't always helpful, but suggesting a concise element-wise fix is harder. I think the error is actually produced by `(x>0).__bool__()`, which is called (by the interpreter?) any time the code expects a boolean value - such as `if`, `or`. `pandas` and `sympy` have there own versions of the `ambiguity` error. – hpaulj Jul 22 '23 at 15:52
  • Yes, the error is produced by boolean conversion. There are various fixes depending on what the user is trying to do, and understanding the problem is a general topic that is well covered at the now-linked duplicate. – Karl Knechtel Jul 22 '23 at 18:16

2 Answers2

3

Use numpy.where:

Return elements chosen from x or y depending on condition.

e = np.where(a > b, 2*a+6*c, 3*c + 4*d)
0
In [370]: a = np.array([[3.5,6,8,2]])
     ...: b = np.array([[6,2,8,2]])
     ...: c = np.array([[2,3,7,5]])
     ...: d = np.array([[3,2,5,1]])
     ...: 
In [371]: a.shape
Out[371]: (1, 4)
In [372]: a[0].shape
Out[372]: (4,)

The problem with the if is that a>b is an array. There's no one True/False value to "switch" on:

In [373]: a>b
Out[373]: array([[False,  True, False, False]])

where does the array "switch"; an equivalent way is:

In [376]: mask = a>b
In [377]: e = 3*c + 4*d
In [378]: e
Out[378]: array([[18, 17, 41, 19]])
In [379]: e[mask] = 2*a[mask] + 6*c[mask]
In [380]: e
Out[380]: array([[18, 30, 41, 19]])

np.where itself does not iterate (many pandas users seem assume it does). It works with the whole arrays, the condition array (my mask) and the whole array values.

To use the if, we have to work with scalar values, not arrays. Wrap the if/else in a loop. For example:

In [381]: alist = []
In [382]: for i,j,k,l in zip(a[0],b[0],c[0],d[0]):
     ...:     if i>j:
     ...:         f = 2*i+6*k
     ...:     else:
     ...:         f = 3*k+4*l
     ...:     alist.append(f)
     ...: 
In [383]: alist
Out[383]: [18, 30.0, 41, 19]

This works because i and j are single numbers, not arrays.

hpaulj
  • 221,503
  • 14
  • 230
  • 353