Using numpy.where() to compare numbers in an array to an interval - python

I have an array of numbers:
my_arr = np.array([n, n+1, n+2 ... , m-1, m]
I want to create an array of Booleans which indicate which numbers are in some (closed) interval, [A,B], to operate on some other related array that has the same shape. There are two cases:
Case 1: B >= m or A <= n
This case is trivial; the interval can be fully described with only one Boolean expression, and np.where() provides the solution to testing my array; e.g.:
my_boolean_arr = np.where(my_arr >= A)
or it's equivalent for B. This works.
Case 2: n <= A and m >= B
Here, I run into problems. I can no longer reduce my interval expression into a "single" Boolean expression. Python allows me to come close: the expression A < x < B will return a single (correct) Boolean. However,
my_boolean_arr = np.where(A <= my_arr <= B)
now fails:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
So, Two questions. First, how do I make this work? Second, why does this fail?

Operators "and" and "or" are not defined for numpy arrays.
In your case, you can use np.logical_and instead:
my_boolean_arr = np.logical_and(my_arr>=A, my_arr<=B)
https://numpy.org/doc/stable/reference/generated/numpy.logical_and.html
Alternative way is to use operator &
my_boolean_arr = (my_arr>=A) & (my_arr<=B)

Related

comparing numpy arrays element-wise setting an element-wise result

possibly this has been asked before, but I have a hard time finding a corresponding solution, since I can't find the right keywords to search for it.
One huge advantage of numpy arrays that I like is that they are transparent for many operations.
However in my code I have a function that has a conditional statement in the form (minimal working example):
import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([1, 1, 3])
def func(x, y):
if x > y:
z = 1
else:
z = 2
return z
func(arr1, arr2) obviously results in an error message:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I do understand what the problem here is and why it can't work like this.
What I would like to do here is that x > y is evaluated for each element and then an array z is returned with the corresponding result for each comparison. (Needs to ensure of course that the arrays are of equal length, but that's not a problem here)
I know that I could do this by changing func such that it iterates over the elements, but since I'm trying to improve my numpy skills: is there a way to do this without explicit iteration?
arr1 > arr2 does exactly what you'd hope it does: compare each element of the two arrays and build an array with the result. The result can be used to index in any of the two arrays, should you need to. The equivalent of your function, however, can be done with np.where:
res = np.where(arr1 > arr2, 1, 2)
or equivalently (but slightly less efficiently), using the boolean array directly:
res = np.ones(arr1.shape)
res[arr1 <= arr2] = 2 # note that I have to invert the condition to select the cells where you want the 2

Bisection_method in array - numpy

I have an equation where my unknown is h and TR which is an array (2D).
I would like to solve the equation below by bisect method and as a result get a new array(2D), which will represent my h
Tpow,k,t - constant
h = np.empty_like(TR)
def f(h):
return (-TR+(Tpow-T1)*(1-exp((h**2*alfa*t)/k**2)*(1.0-erf(h*sqrt(alfa*t)/k))))
for i in range(len(TR)):
for j in range(len(TR[0])):
h[i][j] = scipy.optimize.bisect(f,0,600)
np.any() accepts a boolean array and returns a single boolean.
You are passing an array of floats, and then doing the comparison on the single boolean output. This is almost certainly not what you want. So instead of this:
if np.any(f(a)*f(b))>0:
do this:
if np.any(f(a) * f(b) > 0):
i.e., keep your comparisons inside np.any or np.all() Repeat for all the rest

Check for a condition within an array

I would like to check a condition inside an array and perform an operation on the position where the condition is met. For example, this piece of code does the job:
res = somefunction(x)
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if not 6 < res[i,j] < 18:
x[i,j] = float('nan')
But I thought a faster (and shorter) way would maybe be something like this:
x[not 6 < somefunction(x) < 18] = float('nan')
But python gives the error that condition checking doesn't work in array with more than element. Is there a way to make my code go faster?
You can't use not or chained comparisons with arrays, since neither not nor chained comparisons can be implemented to broadcast.
Split the chained comparison into two comparisons, and use ~ and & instead of not and and, since NumPy uses the bitwise operators for boolean operations on boolean arrays:
x[~((6 < res) & (res < 18))] = numpy.nan

Calculation between values in numpy array

New to python and need some help. I have a numpy array tuple with a shape of (1, 8760) with numbers within each of the 8760 locations. I've been trying to calculate if the values is between -2 and 2 then my new variable will be 0 else just keep the same value in the new variable. Here is what I tried and many others but I probably don't understand the array concept fully.
for x in flow:
if 2 > x < -2:
lflow = 0
else:
lflow = flow
I get this error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
From what I read those functions gives me a true or false but I want to calculate of value instead of telling me if it matches or not. Please help.
Thanks
If your shape is (1,8760) an array of 8760 elements is assigned to x in your iteration, because the loop iterates the first axis containing one element of size 8760.
Furthermore I'd suggest to use "where" function instead of a loop:
# create a random array with 100 values in the range [-5,5]
a = numpy.random.random(100)*10 - 5
# return an array with all elements within that range set to 0
print numpy.where((a < -2) | (a > 2), a, 0)
Numpy uses boolean masks to select or assign values to arrays in bulk. For example, given the array
A = np.array([-3,-1,-2,0,1,5,2])
This mask represents all the values in A that are less than -2 or greater than 2
mask = (A < -2) | (A > 2)
Then use it to assign those values to 0
A[mask] = 0
This is much faster than using a regular loop in python, since numpy will perform this operation in c or fortran code

Numpy Select indices with complex conditions

Simple question... I hope...
I've got a matrix, a , of size (n x m)
a = np.matrix([[1,2,3],[3,2,1],[6,4,1]])
and I'd like to extract a bool matrix, b, of size (n x m) for the following condition;
b = 3 < a > 7 and a != 6
However it is throwing the following error.
The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
Any help with this because I'm quite stuck.
Cheers!
You can't use and with arrays as you're trying to compare a single value with an array you have to use &, also you need to enclose the conditions in parentheses due to operator precedence:
In [56]:
a[(a > 3 ) & (a < 7) & (a != 6)]
Out[56]:
matrix([[4]])

Categories