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

222

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

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

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 ()

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

Homunculus Reticulli
источник
1
Панды также предлагают документацию для этого
Грег

Ответы:

164

rявляется массивом nume (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().

unutbu
источник
2
Ты прав. Оригинальный код был верным. Ошибка, кажется, лежит где-то еще в коде.
Гомункул Ретулли
2
Отличное объяснение. Это подразумевает, однако, что NumPy довольно неэффективен: он полностью оценивает оба логических массива, тогда как эффективная реализация будет оценивать cond1 (i) && cond2 (i) внутри одного цикла и пропускать cond2, если cond1 не является истиной.
Иоахим W
@JoachimWuttke: Хотя np.allи np.anyспособны к короткому замыканию, переданный ему аргумент оценивается раньше np.allили np.anyимеет шанс на короткое замыкание. Чтобы добиться большего успеха, в настоящее время вам нужно написать специальный код C / Cython, похожий на этот .
unutbu
Это не лучший ход, который они могли бы сделать ... andи &вовсе не одно и то же, и у них даже нет одинакового приоритета.
Камион
47

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

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

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

selected  = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]
Ецин Чжан
источник
34

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

Однако boolon on 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.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( |оператор):

>>> 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:

MSeifert
источник
2

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

df = df.dropna()

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

Томер Бен Дэвид
источник
0

Это типичное сообщение об ошибке также отображается во время if-statementсравнения, где есть массив и, например, bool или int. Смотрите, например:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

Этот пункт имеет набор данных в виде массива, а bool - это «открытая дверь» ... Trueили False.

Если функция обернута внутри, try-statementвы получите except Exception as error:сообщение без типа ошибки:

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

ZF007
источник
-6

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

Анураг Гупта
источник