ValueError: Значение истины массива с более чем одним элементом неоднозначно. Используйте команды a.any() или a.all()

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

Я изменил код:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

TO:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) and (r["dt"] <= enddate))
selected = r[mask]

К моему удивлению, я получил довольно загадочное сообщение об ошибке:

ValueError: значение истинности массива с более чем одним элементом неоднозначный. Используйте a.any() или a.all()

Почему подобная ошибка не испускалась при использовании побитовой операции - и как это исправить?

Ответ 1

r это массив numey (rec). Так что r["dt"] >= startdate также является (логическим) массив. Для пустых массивов операция & возвращает поэлементно и из двух логические массивы.

Разработчики NumPy считают, что нет единого общепринятого способа оценки массив в логическом контексте: это может означать True, если какой-либо элемент True, или это может означать True, если все элементы имеют значение True, или True, если массив имеет ненулевую длину, просто назвать три возможности.

Поскольку разные пользователи могут иметь разные потребности и разные предположения, Разработчики NumPy отказались угадывать и вместо этого решили поднять ValueError всякий раз, когда кто-то пытается оценить массив в логическом контексте. Применяя and к два пустых массива приводят к оценке двух массивов в логическом контексте ( вызов __bool__ в Python3 или __nonzero__ в Python2).

Ваш оригинальный код

mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

выглядит правильно. Однако, если вы хотите and, то вместо a and b используйте (a-b).any() или (a-b).all().

Ответ 2

У меня была такая же проблема (то есть индексация с несколькими условиями, здесь она находила данные в определенном диапазоне дат). (a-b).any() или (a-b).all(), кажется, не работают, по крайней мере, для меня.

В качестве альтернативы я нашел другое решение, которое идеально подходит для моей желаемой функциональности (Значение истинности массива с более чем одним элементом неоднозначно при попытке индексировать массив).

Вместо того, чтобы использовать предложенный код выше, просто используйте numpy.logical_and(a,b). Здесь вы можете переписать код как

selected  = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]

Ответ 3

Причиной исключения является то, что and неявно вызывает bool. Сначала в левом операнде и (если левый операнд равен True), то в правом операнде. Таким образом, x and y эквивалентны bool(x) and bool(y).

Однако bool на 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: np.bitwise_and (& оператор)

>>> np.logical_and(arr > 1, arr < 3)
array([False,  True, False], dtype=bool)

>>> np.bitwise_and(arr > 1, arr < 3)
array([False,  True, False], dtype=bool)

>>> (arr > 1) & (arr < 3)
array([False,  True, False], dtype=bool)

и bitwise_or (| operator):

>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False,  True], dtype=bool)

>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False,  True], dtype=bool)

>>> (arr <= 1) | (arr >= 3)
array([ True, False,  True], dtype=bool)

Полный список логических и двоичных функций можно найти в документации NumPy:

Ответ 4

если вы работаете с pandas, для меня проблема была в том, что я пытался выполнить вычисления, когда у меня были значения NA, решение было запустить:

df = df.dropna()

И после этого расчет не удался.

Ответ 5

попробуйте это => numpy.array(r) или numpy.array(yourvariable), а затем команду, чтобы сравнить все, что вы хотите.