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), а затем команду, чтобы сравнить все, что вы хотите.