ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
ValueError: истинное значение массива с более чем одним элементом неоднозначно. Используйте a.any() или a.all()
Пусть x - массив NumPy . Следующее:
(x > 1) and (x < 3)
Выдает сообщение об ошибке:
ValueError: истинное значение массива с более чем одним элементом неоднозначно. Используйте a.any() или a.all()
Как мне это исправить?
Переведено автоматически
Ответ 1
Если a и b являются логическими массивами NumPy, то & операция возвращает поэлементное значение-and из них:
a & b
Который возвращает логический массив. Чтобы свести это к одному логическому значению, используйте либо
(a & b).any()
или
(a & b).all()
Примечание: если a и b являются нелогическими массивами, вместо этого используйте (a - b).any() or (a - b).all().
Обоснование
Разработчики NumPy посчитали, что не существует единого общепринятого способа вычисления массива в логическом контексте: это может означать, что True если какой-либо элемент является True, или это может означать, что True если все элементы являются True, или True если массив имеет ненулевую длину, просто чтобы назвать три возможности.
Поскольку у разных пользователей могут быть разные потребности и разные предположения, разработчики NumPy отказались угадывать и вместо этого решили вызывать a ValueError всякий раз, когда кто-то пытается оценить массив в логическом контексте. Применение and к двум массивам numpy приводит к тому, что два массива вычисляются в логическом контексте (путем вызова __bool__ в Python3 или __nonzero__ в Python2).
Ответ 2
У меня была такая же проблема (т. Е. Индексирование с несколькими условиями, здесь это поиск данных в определенном диапазоне дат). (a-b).any() Или (a-b).all(), похоже, не работает, по крайней мере, для меня.
Причина исключения в том, что and неявный вызов bool. Сначала для левого операнда и (если левый операнд True) затем для правого операнда. So x and y эквивалентно bool(x) and bool(y).
Однако bool на a numpy.ndarray (если он содержит более одного элемента) будет генерироваться исключение, которое вы видели:
>>> import numpy as np >>> arr = np.array([1, 2, 3]) >>> bool(arr) ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
bool() Вызов неявен в and, но также и в if, while, or , поэтому любой из следующих примеров также завершится ошибкой:
>>> arr and arr ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> if arr: pass ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> while arr: pass ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr or arr ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
В Python есть больше функций и операторов, которые скрывают, например, bool вызовы, 2 < x < 10 это просто другой способ записи 2 < x and x < 10. И and вызовет bool: bool(2 < x) and bool(x < 10).
Поэлементным эквивалентом для and была бы np.logical_and функция, аналогично вы могли бы использовать np.logical_or как эквивалент для or.
Для логических массивов - а сравнения типа <, <=, ==, !=>= и > в массивах NumPy возвращают логические массивы NumPy - вы также можете использовать поэлементные побитовые функции (и операторы): np.bitwise_and (& operator)
Эта ошибка возникает каждый раз, когда код пытается преобразовать массив Numpy в логическое значение (т. Е. Проверить его истинное значение, как описано в сообщении об ошибке). Для данного массива a это может произойти:
Неявно используя встроенные any и all функции. (Они могут принимать один массив, независимо от того, сколько измерений он имеет; но не могут принимать список, кортеж, набор и т.д. Массивов.)
Массивы и сравнения Numpy (==, !=, <, ><=, >=, ,,,)
Сравнения имеют особое значение для массивов Numpy. Мы рассмотрим здесь оператор ==; остальные ведут себя аналогично. Предположим, что у нас есть
import numpy as np >>> a = np.arange(9) >>> b = a % 3 >>> a array([0, 1, 2, 3, 4, 5, 6, 7, 8]) >>> b array([0, 1, 2, 0, 1, 2, 0, 1, 2])
Тогда, a == bне означает "дайте ответ True или False: a равно b?", как это обычно означало бы. Вместо этого он будет сравнивать значения поэлементно и вычислять массив логических результатов для этих сравнений:
>>> a == b array([ True, True, True, False, False, False, False, False, False])
Другими словами, он выполняет тот же вид трансляции, что и математические операторы (например, b = a % 3).
Не имеет смысла использовать этот результат для if инструкции, потому что неясно, что делать: должны ли мы вводить if блок, потому что некоторые значения совпали? Или мы должны ввести else блок, потому что некоторые значения не совпадают? Здесь Numpy применяет важный принцип из Zen of Python: "Перед лицом двусмысленности откажитесь от соблазна угадать".
Таким образом, Numpy только позволит преобразовать массив в bool если он содержит ровно один элемент. (В некоторых более старых версиях оно также преобразуется в False для пустого массива; но есть веские логические причины, почему это также следует рассматривать как неоднозначное.)
Аналогично, сравнение a == 4не проверит, равен ли массив целому числу (конечно, ни один массив никогда не может быть равен какому-либо целому числу). Вместо этого он будет транслировать сравнение по всему массиву, выдавая аналогичный массив результатов:
Если код явно преобразуется в bool, выберите между применением .any или .all к результату, в зависимости от обстоятельств. Как следует из названий, .any свернет массив до единственного логического значения, указывающего, было ли какое-либо значение истинным; .all проверит, были ли истинны все значения.
>>> (a == 4).all() # `a == 4` contains some `False` values False >>> (a == 4).any() # and also some `True` values True >>> a.all() # We can check `a` directly as well: `0` is not truthy, False >>> a.any() # but other values in `a` are. True
Если цель состоит в том, чтобы преобразовать a в логическое значение по элементам, используйте a.astype(bool), или (только для числовых вводов) a != 0.
Если в коде используется логическая логика (and/or/not), используйте побитовые операторы (&/|/~ соответственно):
Для списка (или другой последовательности) массивов, которые необходимо объединить одинаковым образом (т. Е. То, что делают встроенные модули all и any), вместо этого создайте соответствующий (N + 1)-мерный массив и используйте np.all или np.any вдоль оси 0:
>>> a = np.arange(100) # a larger array for a more complex calculation >>> sieves = [a % p for p in (2, 3, 5, 7)] >>> all(sieves) # won't work Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() >>> np.all(np.array(sieves), axis=0) # instead: array([False, True, False, False, False, False, False, False, False, False, False, True, False, True, False, False, False, True, False, True, False, False, False, True, False, False, False, False, False, True, False, True, False, False, False, False, False, True, False, False, False, True, False, True, False, False, False, True, False, False, False, False, False, True, False, False, False, False, False, True, False, True, False, False, False, False, False, True, False, False, False, True, False, True, False, False, False, False, False, True, False, False, False, True, False, False, False, False, False, True, False, False, False, False, False, False, False, True, False, False])
Исправление if
Во-первых, имейте в виду, что если в коде есть if оператор, который использует неработающее выражение (например, if (a % 3 == 0) or (a % 5 == 0):), то выражение также нужно будет исправить.
Как правило, явное преобразование в bool (с использованием .all() или .any(), как указано выше) позволит избежать исключения:
>>> a = np.arange(20) # enough to illustrate this >>> if ((a % 3 == 0) | (a % 5 == 0)).any(): ... print('there are fizzbuzz values') ... there are fizzbuzz values
но это может не делать того, что требуется:
>>> a = np.arange(20) # enough to illustrate this >>> if ((a % 3 == 0) | (a % 5 == 0)).any(): ... a = -1 ... >>> a -1
Если цель состоит в том, чтобы оперировать каждым значением, где условие истинно, то естественный способ сделать это - использовать результирующий массив в качестве маски. Например, чтобы присвоить новое значение везде, где условие истинно, просто проиндексируйте в исходный массив с вычисленной маской и присвоите:
Интерфейс Pandas для решения проблемы немного сложнее - и его лучше всего понять, прочитав вопросы и ответы. Вопрос конкретно касается рядов, но логика обычно применима и к фреймам данных. Пожалуйста, также ознакомьтесь с Условием If с фреймом данных для получения более конкретных рекомендаций по применению условной логики к фрейму данных.