## 问题：脾气暴躁的地方有多个条件

`` dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]``

`` (np.where(dists <= r + dr))``

I have an array of distances called dists. I want to select dists which are between two values. I wrote the following line of code to do that:

`````` dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]
``````

However this selects only for the condition

`````` (np.where(dists <= r + dr))
``````

If I do the commands sequentially by using a temporary variable it works fine. Why does the above code not work, and how do I get it to work?

Cheers

## 回答 0

``dists[abs(dists - r - dr/2.) <= dr/2.]``

``dists[(dists >= r) & (dists <= r+dr)]``

`` dists[(np.where((dists >= r) & (dists <= r + dr)))]``

``````In [230]: dists = np.arange(0,10,.5)
In [231]: r = 5
In [232]: dr = 1

In [233]: np.where(dists >= r)
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)

In [234]: np.where(dists <= r+dr)
Out[234]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)

In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
Out[235]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)``````

``````In [236]: dists >= r
Out[236]:
array([False, False, False, False, False, False, False, False, False,
False,  True,  True,  True,  True,  True,  True,  True,  True,
True,  True], dtype=bool)

In [237]: dists <= r + dr
Out[237]:
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
True,  True,  True,  True, False, False, False, False, False,
False, False], dtype=bool)

In [238]: (dists >= r) & (dists <= r + dr)
Out[238]:
array([False, False, False, False, False, False, False, False, False,
False,  True,  True,  True, False, False, False, False, False,
False, False], dtype=bool)``````

``````In [239]: np.where((dists >= r) & (dists <= r + dr))
Out[239]: (array([10, 11, 12]),)

In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
Out[240]: array([ 5. ,  5.5,  6. ])``````

``````In [241]: dists[(dists >= r) & (dists <= r + dr)]
Out[241]: array([ 5. ,  5.5,  6. ])``````

The best way in your particular case would just be to change your two criteria to one criterion:

``````dists[abs(dists - r - dr/2.) <= dr/2.]
``````

It only creates one boolean array, and in my opinion is easier to read because it says, (Though I’d redefine `r` to be the center of your region of interest instead of the beginning, so `r = r + dr/2.`) But that doesn’t answer your question.

The answer to your question:
You don’t actually need `where` if you’re just trying to filter out the elements of `dists` that don’t fit your criteria:

``````dists[(dists >= r) & (dists <= r+dr)]
``````

Because the `&` will give you an elementwise `and` (the parentheses are necessary).

Or, if you do want to use `where` for some reason, you can do:

`````` dists[(np.where((dists >= r) & (dists <= r + dr)))]
``````

Why:
The reason it doesn’t work is because `np.where` returns a list of indices, not a boolean array. You’re trying to get `and` between two lists of numbers, which of course doesn’t have the `True`/`False` values that you expect. If `a` and `b` are both `True` values, then `a and b` returns `b`. So saying something like `[0,1,2] and [2,3,4]` will just give you `[2,3,4]`. Here it is in action:

``````In [230]: dists = np.arange(0,10,.5)
In [231]: r = 5
In [232]: dr = 1

In [233]: np.where(dists >= r)
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)

In [234]: np.where(dists <= r+dr)
Out[234]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)

In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
Out[235]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)
``````

What you were expecting to compare was simply the boolean array, for example

``````In [236]: dists >= r
Out[236]:
array([False, False, False, False, False, False, False, False, False,
False,  True,  True,  True,  True,  True,  True,  True,  True,
True,  True], dtype=bool)

In [237]: dists <= r + dr
Out[237]:
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
True,  True,  True,  True, False, False, False, False, False,
False, False], dtype=bool)

In [238]: (dists >= r) & (dists <= r + dr)
Out[238]:
array([False, False, False, False, False, False, False, False, False,
False,  True,  True,  True, False, False, False, False, False,
False, False], dtype=bool)
``````

Now you can call `np.where` on the combined boolean array:

``````In [239]: np.where((dists >= r) & (dists <= r + dr))
Out[239]: (array([10, 11, 12]),)

In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
Out[240]: array([ 5. ,  5.5,  6. ])
``````

Or simply index the original array with the boolean array using fancy indexing

``````In [241]: dists[(dists >= r) & (dists <= r + dr)]
Out[241]: array([ 5. ,  5.5,  6. ])
``````

## 回答 1

``np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))``

The accepted answer explained the problem well enough. However, the the more Numpythonic approach for applying multiple conditions is to use numpy logical functions. In this ase you can use `np.logical_and`:

``````np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))
``````

## 回答 2

``````ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) and (ar<6), 'yo', ar)

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

``````ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) & (ar<6), 'yo', ar)

Output:
array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')``````

## 更新

``````np.where( ar>3 & ar<6, 'yo', ar)
np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)``````

``````np.where( (ar>3) & (ar<6), 'yo', ar)
np.where( (array([False,  True,  True,  True, False,  True, False,  True])) & (array([ True,  True,  True, False,  True,  True,  True, False])), 'yo', ar)``````

``np.where( array([False,  True,  True, False, False,  True, False, False]),  'yo', ar)``

One interesting thing to point here; the usual way of using OR and AND too will work in this case, but with a small change. Instead of “and” and instead of “or”, rather use Ampersand(&) and Pipe Operator(|) and it will work.

When we use ‘and’:

``````ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) and (ar<6), 'yo', ar)

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

When we use Ampersand(&):

``````ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) & (ar<6), 'yo', ar)

Output:
array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')
``````

And this is same in the case when we are trying to apply multiple filters in case of pandas Dataframe. Now the reasoning behind this has to do something with Logical Operators and Bitwise Operators and for more understanding about same, I’d suggest to go through this answer or similar Q/A in stackoverflow.

## UPDATE

A user asked, why is there a need for giving (ar>3) and (ar<6) inside the parenthesis. Well here’s the thing. Before I start talking about what’s happening here, one needs to know about Operator precedence in Python.

Similar to what BODMAS is about, python also gives precedence to what should be performed first. Items inside the parenthesis are performed first and then the bitwise operator comes to work. I’ll show below what happens in both the cases when you do use and not use “(“, “)”.

Case1:

``````np.where( ar>3 & ar<6, 'yo', ar)
np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)
``````

Since there are no brackets here, the bitwise operator(`&`) is getting confused here that what are you even asking it to get logical AND of, because in the operator precedence table if you see, `&` is given precedence over `<` or `>` operators. Here’s the table from from lowest precedence to highest precedence.

It’s not even performing the `<` and `>` operation and being asked to perform a logical AND operation. So that’s why it gives that error.

One can check out the following link to learn more about: operator precedence

Now to Case 2:

If you do use the bracket, you clearly see what happens.

``````np.where( (ar>3) & (ar<6), 'yo', ar)
np.where( (array([False,  True,  True,  True, False,  True, False,  True])) & (array([ True,  True,  True, False,  True,  True,  True, False])), 'yo', ar)
``````

Two arrays of True and False. And you can easily perform logical AND operation on them. Which gives you:

``````np.where( array([False,  True,  True, False, False,  True, False, False]),  'yo', ar)
``````

And rest you know, np.where, for given cases, wherever True, assigns first value(i.e. here ‘yo’) and if False, the other(i.e. here, keeping the original).

That’s all. I hope I explained the query well.

## 回答 3

``````>>> # function which returns True when constraints are satisfied.
>>> func = lambda d: d >= r and d<= (r+dr)
>>>
>>> # Apply constraints element-wise to the dists array.
>>> result = np.vectorize(func)(dists)
>>>
>>> result = np.where(result) # Get output.``````

I like to use `np.vectorize` for such tasks. Consider the following:

``````>>> # function which returns True when constraints are satisfied.
>>> func = lambda d: d >= r and d<= (r+dr)
>>>
>>> # Apply constraints element-wise to the dists array.
>>> result = np.vectorize(func)(dists)
>>>
>>> result = np.where(result) # Get output.
``````

You can also use `np.argwhere` instead of `np.where` for clear output. But that is your call :)

Hope it helps.

## 回答 4

``np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0])``

Try:

``````np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0])
``````

## 回答 5

``dists[((dists >= r) & (dists <= r+dr))]``

This should work:

``````dists[((dists >= r) & (dists <= r+dr))]
``````

The most elegant way~~

## 回答 6

``````import numpy as np
dist = np.array([1,2,3,4,5])
r = 2
dr = 3
np.where(np.logical_and(dist> r, dist<=r+dr))``````

Try:

``````import numpy as np
dist = np.array([1,2,3,4,5])
r = 2
dr = 3
np.where(np.logical_and(dist> r, dist<=r+dr))
``````

Output: (array([2, 3]),)

You can see Logic functions for more details.

## 回答 7

``````import numpy as np

ar = np.array([3,4,5,14,2,4,3,7])

print [X for X in list(ar) if (X >= 3 and X <= 6)]

>>>
[3, 4, 5, 4, 3]``````

I have worked out this simple example

``````import numpy as np

ar = np.array([3,4,5,14,2,4,3,7])

print [X for X in list(ar) if (X >= 3 and X <= 6)]

>>>
[3, 4, 5, 4, 3]
``````