0

I'm trying to write a script that simulates a system of chemical reactions over time. One of the inputs to the function is the following array:

popul_num = np.array([200, 100, 0, 0])

Which contains the number of discrete molecules of each species in the system. Part of the main function has an if statement that's meant to check that number of molecules is positive. if it is processed to the next iteration, else break out of the whole simulation

if popul_num.any() < 0: # Any method isn't working! --> Does .any() work on arrays or just lists? 
        print("Break out of loop negative molecule numbers")
        tao_all = tao_all[0:-1]
        popul_num_all = popul_num_all[0:-1]       
    else:
        break

I've used the .any() to try find if any element of the popul_num array is negative. But it doesn't work, it doesn't throw an error, the system just never enters the if statement and I can't figure out why?

I've just ran the program and the final number of molecules the system returned was: [135 -19 65 54] the program should have broken out before the second element got to -19.

Any suggestions?

Cheers

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
Mike5298
  • 377
  • 1
  • 13
  • any will return True when at least one of the elements is True; `any(iterable)` – Aditya Jun 27 '20 at 08:36
  • Just do `if np.any(popul_num < 0): # do_stuff` or `if (popul_num < 0).any(): #do_stuff`. You start by constructing a boolean array _before_ applying `any`. – alani Jun 27 '20 at 08:50

5 Answers5

2

You should use .any() on a boolean array after doing the comparison, not on the values of popul_num themselves. It will return True if any of the values of the boolean array are True, otherwise False.

In fact, .any() tests for any "truthy" values, which for integers means non-zero values, so it will work on an array of integers to test if any of them are non-zero, which is what you are doing, but this is not testing the thing that you are interested in knowing. The code then compounds the problem by doing an < 0 test on the boolean value returned by any, which always evaluates True because boolean values are treated as 0 and 1 (for False and True respectively) in operations involving integers.

You can do:

if (popul_num < 0).any():
    do_whatever

Here popul_num < 0 is a boolean array containing the results of element-by-element comparisons. In your example:

>>> popul_num < 0
array([False, False, False, False], dtype=bool)

You are, however, correct to use array.any() (or np.any(array)) rather than using the builtin any(). The latter happens to work for a 1-d array, but would not work with more dimensions. This is because iterating e.g. over a 4d array (which is what the builtin any() would do) gives a sequence of 3d arrays, not the individual elements.

There is also similarly .all(). The above test is equivalent to:

if not (popul_num >= 0).all():
alani
  • 12,573
  • 2
  • 13
  • 23
1

any() is a method for use on iterables. It returns True if any of the items in the iterable are truthy. You want something more like:

if any([True for x in popul_num if x > 0]):
  print("at least one element was greater than zero!")
Frank
  • 459
  • 2
  • 9
1

The any method of numpy arrays returns a boolean value, so when you write:

if popul_num.any() < 0:

popul_num.any() will be either True (=1) or False (=0) so it will never be less than zero. Thus, you will never enter this if-statement.

What any() does is evaluate each element of the array as a boolean and return whether any of them are truthy. For example:

>>> np.array([0.0]).any()
False

>>> np.array([1.0]).any()
True

>>> np.array([0.0, 0.35]).any()
True

As you can see, Python/numpy considers 0 to be falsy and all other numbers to be truthy. So calling any on an array of numbers tells us whether any number in the array is nonzero. But you want to know whether any number is negative, so we have to transfrom the array first. Let's introduce a negative number into your array to demonstrate.

>>> popul_num = np.array([200, 100, 0, -1])
>>> popul_num < 0  # Test is applied to all elements in the array
np.ndarray([False, False, False, True])
>>> (popul_num < 0).any()
True

You asked about any on lists versus arrays. Python's builtin list has no any method:

>>> [].any()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'any'

There is a builtin function (not method since it doesn't belong to a class) called any that serves the same purpose as the numpy .any method. These two expressions are logically equivalent:

any(popul_num < 0)

(popul_num < 0).any()

We would generally expect the second one to be faster since numpy is implemented in C. However only the first one will work with non-numpy types such as list and set.

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
0

any() returns True, if at least one of the elements is True:

L1 = [False, False, False]
any(L1)
# >>> False

L1 = [True, False, False]
any(L1)
# >>> True

L1 = ["Hi", False, False]
any(L1)
# >>> True

L1 = []
any(L1)
# >>> False

CMinusMinus
  • 426
  • 1
  • 3
  • 11
0

any() returns True if at least one element in a NumPy array evaluates to True and np.all test whether all array elements along a given axis evaluate to True. What you need to solve your problem is the all method.

Mateo Lara
  • 827
  • 2
  • 12
  • 29