Как работает двустороннее неравенство Pythons? и почему это не работает для массивов numpy?

#python #numpy #comparison #operators #boolean-expression

#python #numpy #сравнение #операторы #логическое выражение

Вопрос:

В Python вы можете сделать следующее;

 >>> 3 < 4 < 5
True
>>> 3 < 4 < 4
False
 

Как это работает? Я бы подумал, что 4 < 5 это вернет логическое значение, и поэтому 3 < True должно вернуться False , или 3 < 4 должно вернуть логическое True < 4 значение, и поэтому, возможно, должно вернуться True , если True может быть приведено как целое число 1 ?.

И почему это не работает для массивов numpy?

 >>> 1 < np.array([1, 2, 3]) < 3
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
 

Можно ли заставить его работать для массивов numpy?

Комментарии:

1. Оно оценивается как 3 < 4 and 4 < 5 . Кроме того, ошибка numpy, которую вы получаете, не имеет ничего общего с тем фактом, что вы объединяете операторы вместе. Скорее, это связано с тем фактом, что достоверность массива numpy с более чем одним значением неоднозначна, как говорится в сообщении об ошибке. Вы бы получили ту же ошибку, если бы просто сделали bool(np.array([1, 2, 3])) .

2. @PaulM. Тогда почему это не работает для массивов numpy? « 1 < np.array([1, 2, 3]) и np.array([1, 2, 3]) < 3 Трассировка (последний последний вызов): файл «<input>», строка 1, в <module> ValueError: истинное значениемассив с более чем одним элементом неоднозначен. Используйте.any() или.all() « Тогда почему я не могу сделать; « np.array([1]) < np.array([1, 2, 3]) < np.array([3]) Обратная трассировка (самая последняявызовите последний): Файл «<input>», строка 1, в <module> Ошибка значения: значение истинности массива с более чем одним элементом неоднозначно. Используйте.any() или.all() «

3. К вашему сведению, эта функция существует как минимум с версии 2.7 , которая сейчас является EOL, поэтому я удалил эту часть вопроса, поскольку это не очень важно.

4. @wjandrea хорошо, мой плохой, спасибо за редактирование.

5. @PaulM. — ваша перезапись неверна, поскольку вы применяете all() к исходному массиву numpy, а не к результату сравнения его с целым числом. Упрощение вашей перезаписи 0 < True < 5 , что, очевидно, бесполезно.

Ответ №1:

Согласно документам Python:

Сравнения могут быть скомпонованы произвольно, например, x < y <= z эквивалентно x < y and y <= z , за исключением того, что вычисляется y только один раз (но в обоих случаях z вообще не вычисляется, когда x < y оказывается ложным).

Итак, ваш пример эквивалентен:

 1 < np.array([1, 2, 3]) and np.array([1, 2, 3]) < 3
 

таким образом, ожидается, что каждый подтерм приведет к логическому значению. Но подтерминал:

 1 < np.array([1, 2, 3])
 

в результате создается новый массив numpy, содержащий:

 [False, True, True]
 

Именно это значение Python пытается интерпретировать как логическое значение. Это не удается сделать, выдавая сообщение об ошибке:

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

Я ожидаю, что желаемое выражение здесь:

 (1 < np.array([1, 2, 3])).all() and (np.array([1, 2, 3]) < 3).all()
 

который нельзя упростить, чтобы использовать цепочку сравнения.

Комментарии:

1. Именно evaluated only once это делает двустороннее выражение особенным. В противном случае это просто синтаксический ярлык. Поэтому необходимость использовать два отдельных сравнения в numpy не является большой потерей. Поскольку numpy сравнения выполняются по элементам, у вас есть выбор при создании логических комбинаций.

2. @hpaulj — Я не согласен ни с чем, что вы говорите. Более эквивалентное выражение с точки зрения эффективности или даже функции может включать извлечение создания массива numpy в отдельную функцию, чтобы это происходило только один раз. Я просто отвечал на вопрос «почему», который не требовал вникания в эту тонкость. Учитывая существование [1, 2, 3] в рассматриваемом выражении, это явно не производственный код.

3. Я должен был указать, что мой комментарий был направлен больше на OP, чем на вас. Я предполагаю, что OP уведомлен о комментариях в ответах, поэтому не пытался добавить @ .

4. @hpaulj — ah. имеет смысл. извините, я воспринял это как направленное на меня.