ValueError: Wartość prawdy tablicy z więcej niż jednym elementem jest niejednoznaczna. Użyj a.any () lub a.all ()

221

Właśnie odkryłem logiczny błąd w moim kodzie, który powodował różnego rodzaju problemy. Nieumyślnie robiłem bitowe AND zamiast logicznego AND .

Zmieniłem kod z:

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

DO:

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

Ku mojemu zaskoczeniu dostałem dość tajemniczy komunikat o błędzie:

ValueError: Wartość prawdy tablicy z więcej niż jednym elementem jest niejednoznaczna. Użyj a.any () lub a.all ()

Dlaczego podobny błąd nie został wyemitowany, gdy korzystam z operacji bitowej - i jak to naprawić?

Homunculus Reticulli
źródło
1
Pandas oferuje również dokumentację na ten temat
Greg

Odpowiedzi:

164

rjest tablicą numpy (rec). Podobnie r["dt"] >= startdatejest z tablicą (boolowską). W przypadku tablic numpy &operacja zwraca elementarną i dwie tablice boolowskie.

Programiści NumPy uważali, że nie ma jednego powszechnie rozumianego sposobu oceny tablicy w kontekście boolowskim: może to oznaczać, Trueże dowolny element jest True, lub może oznaczać, Trueże wszystkie elementy są True, lub Truejeśli tablica ma niezerową długość, wystarczy wymienić trzy możliwości.

Ponieważ różni użytkownicy mogą mieć różne potrzeby i różne założenia, programiści NumPy odmówili zgadywania i zamiast tego postanowili podnieść błąd ValueError za każdym razem, gdy ktoś próbuje ocenić tablicę w kontekście boolowskim. Zastosowanie anddo dwóch tablic numpy powoduje, że dwie tablice są oceniane w kontekście logicznym (przez wywołanie __bool__w Python3 lub __nonzero__Python2).

Twój oryginalny kod

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

wygląda poprawnie. Jeśli jednak chcesz and, to zamiast a and bużywać (a-b).any()lub (a-b).all().

unutbu
źródło
2
Masz rację. Oryginalny kod był poprawny. Błąd wydaje się leżeć gdzie indziej w kodzie.
Homunculus Reticulli
2
Doskonałe wyjaśnienie. Sugeruje to jednak, że NumPy jest dość nieefektywny: w pełni ocenia obie tablice boolowskie, podczas gdy wydajna implementacja ocenia cond1 (i) i& cond2 (i) w jednej pojedynczej pętli i pomija cond2, chyba że cond1 jest prawdziwe.
Joachim W,
@JoachimWuttke: Chociaż np.alli np.anysą w stanie zwarcia, argument przekazany do niej ocenia się przed np.allczy np.anyma szansę na zwarcia. Aby to zrobić lepiej, obecnie musisz napisać specjalny kod C / Cython podobny do tego .
unutbu
47

Miałem ten sam problem (tj. Indeksowanie z wieloma warunkami, tutaj znajduje dane w określonym zakresie dat). (a-b).any()Lub (a-b).all()nie zdają pracy, przynajmniej dla mnie.

Alternatywnie znalazłem inne rozwiązanie, które działa idealnie dla mojej pożądanej funkcjonalności ( wartość prawdy w tablicy z więcej niż jednym elementem jest niejednoznaczna przy próbie indeksowania tablicy ).

Zamiast używać sugerowanego kodu powyżej, po prostu użycie numpy.logical_and(a,b)by działałoby. Tutaj możesz przepisać kod jako

selected  = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]
Yeqing Zhang
źródło
34

Przyczyną wyjątku jest to, że andniejawnie wywołuje bool. Najpierw na lewym operandzie i (jeśli lewy jest True), a następnie na prawym. Więc x and yjest równoważna bool(x) and bool(y).

Jednak boolna a numpy.ndarray(jeśli zawiera więcej niż jeden element) zgłosi wyjątek, który widziałeś:

>>> 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()Połączenie jest ukryte w and, ale również w if, while, or, więc każdy z poniższych przykładów nie powiedzie się także:

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

W Pythonie jest więcej funkcji i instrukcji, które ukrywają boolwywołania, na przykład 2 < x < 10to po prostu inny sposób pisania 2 < x and x < 10. I andwezwie bool: bool(2 < x) and bool(x < 10).

Elementem mądry odpowiednikiem andbyłby np.logical_andfunkcja, podobnie można użyć np.logical_orjako ekwiwalent za or.

Dla tablic logicznych - i porównania podoba <, <=, ==, !=, >=i >na powrót logicznych NumPy tablice tablice numpy - można również użyć elementu mądry bitowe funkcje (i operatorów): np.bitwise_and( &Operator)

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

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

Pełna lista funkcji logicznych i binarnych znajduje się w dokumentacji NumPy:

MSeifert
źródło
2

jeśli pracujesz z pandastym, co rozwiązało dla mnie problem polegał na tym, że próbowałem wykonać obliczenia, gdy miałem wartości NA, rozwiązaniem było uruchomienie:

df = df.dropna()

A potem obliczenia się nie udały.

Tomer Ben David
źródło
0

Ten wpisany komunikat o błędzie pokazuje również podczas if-statementporównania, gdy jest tablica i na przykład bool lub int. Zobacz na przykład:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

Ta klauzula ma zestaw danych jako tablicę, a bool oznacza „otwarte drzwi” ... Truelub False.

W przypadku, gdy funkcja jest zawinięta wewnątrz try-statement, otrzymasz except Exception as error:wiadomość bez jej typu błędu:

Wartość prawdy tablicy z więcej niż jednym elementem jest niejednoznaczna. Użyj a.any () lub a.all ()

ZF007
źródło
-6

spróbuj tego => numpy.array (r) lub numpy.array (twoja zmienna), a następnie polecenie, aby porównać cokolwiek chcesz.

Anurag Gupta
źródło