ValueError: значення істинності масиву з більш ніж одним елементом неоднозначне. Використовуйте a.any () або a.all ()


221

Я щойно виявив логічну помилку в своєму коді, яка викликала всілякі проблеми. Я мимоволі робить побітове І замість логічного І .

Я змінив код з:

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

ДО:

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
Pandas також пропонує документацію на це
Грег,

Відповіді:


164

r- масив numpy (rec). Так r["dt"] >= startdateсамо є (булевий) масив. Для numpy масивів &операція повертає як елемент, так і два булевих масиви.

Розробники 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
Ти маєш рацію. Оригінальний код був правильним. Схоже, помилка лежить десь у коді.
Homunculus Reticulli

2
Відмінне пояснення. Однак, це означає, що NumPy є досить неефективним: він цілком оцінює обидва булеві масиви, тоді як ефективна реалізація оцінюватиме cond1 (i) && cond2 (i) всередині одного циклу та пропускає cond2, якщо cond1 не відповідає дійсності.
Йоахім Ш

@JoachimWuttke: Хоча np.allі np.anyздатний до короткого замикання, переданий йому аргумент оцінюється раніше np.allабо np.anyмає шанс короткого замикання. Для кращого результату на даний момент вам доведеться написати спеціалізований код C / Cython, подібний до цього .
unutbu

47

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

Крім того, я знайшов інше рішення, яке ідеально підходить для моєї бажаної функціональності ( значення істинності масиву з більш ніж одним елементом є неоднозначним при спробі індексувати масив ).

Замість використання запропонованого коду вище, просто використовувати a 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).

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

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


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


-6

спробуйте це => numpy.array (r) або numpy.array (yourvariable) з наступною командою для порівняння того, що ви хочете.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.