Search code examples
pythonarraysnumpyif-statementany

How exactly does the .any() Python method work?


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


Solution

  • 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.