ValueError: o valor verdadeiro de uma matriz com mais de um elemento é ambíguo. Use a.any () ou a.all ()

221

Acabei de descobrir um bug lógico no meu código que estava causando todos os tipos de problemas. Eu estava inadvertidamente fazendo um AND bit a bit em vez de um AND lógico .

Eu mudei o código de:

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

PARA:

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

Para minha surpresa, recebi a mensagem de erro bastante enigmática:

ValueError: o valor verdadeiro de uma matriz com mais de um elemento é ambíguo. Use a.any () ou a.all ()

Por que um erro semelhante não foi emitido quando uso uma operação bit a bit - e como faço para corrigir isso?

Homunculus Reticulli
fonte
1
Pandas documentação ofertas para isso também
Greg

Respostas:

164

ré uma matriz numpy (rec). O mesmo r["dt"] >= startdateacontece com uma matriz (booleana). Para matrizes numpy, a &operação retorna o elemento-e das duas matrizes booleanas.

Os desenvolvedores do NumPy consideraram que não havia uma maneira comum de avaliar uma matriz no contexto booleano: isso poderia significar Truese algum elemento é True, ou Truese todos os elementos são Trueou Truese a matriz tem comprimento diferente de zero, apenas para citar três possibilidades.

Como usuários diferentes podem ter necessidades diferentes e suposições diferentes, os desenvolvedores do NumPy se recusaram a adivinhar e decidiram aumentar um ValueError sempre que alguém tenta avaliar uma matriz no contexto booleano. A aplicação anda duas matrizes numpy faz com que as duas matrizes sejam avaliadas no contexto booleano (chamando __bool__no Python3 ou __nonzero__no Python2).

O seu código original

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

parece correto. No entanto, se você quiser and, em vez de a and busar (a-b).any()ou (a-b).all().

unutbu
fonte
2
Você está certo. O código original estava correto. O bug parece estar em outro lugar no código.
Homunculus Reticulli
2
Excelente explicação. Isso implica, no entanto, que o NumPy é bastante ineficiente: ele avalia totalmente as duas matrizes booleanas, enquanto uma implementação eficiente avalia cond1 (i) && cond2 (i) dentro de um único loop e ignora cond2, a menos que cond1 seja verdadeiro.
Joachim W
@JoachimWuttke: Embora np.alle np.anysão capazes de curto-circuito, o argumento passado para ele é avaliado antes np.allou np.anytem uma chance de curto-circuito. Para fazer melhor, atualmente, você teria que escrever um código C / Cython especializado semelhante a este .
unutbu
47

Eu tive o mesmo problema (ou seja, indexação com várias condições, aqui estão os dados em um determinado período). O (a-b).any()ou (a-b).all()parece não estar funcionando, pelo menos para mim.

Como alternativa, encontrei outra solução que funciona perfeitamente para a funcionalidade desejada ( o valor verdadeiro de uma matriz com mais de um elemento é ambíguo ao tentar indexar uma matriz ).

Em vez de usar o código sugerido acima, simplesmente usar a numpy.logical_and(a,b)funcionaria. Aqui você pode reescrever o código como

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

O motivo da exceção é que andchama implicitamente bool. Primeiro no operando esquerdo e (se o operando esquerdo estiver True), depois no operando direito. Então x and yé equivalente a bool(x) and bool(y).

No entanto, o boolon a numpy.ndarray(se contiver mais de um elemento) lançará a exceção que você viu:

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

A bool()chamada está em implícito and, mas também em if, while, or, então qualquer um dos exemplos a seguir também falhará:

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

Existem mais funções e instruções no Python que ocultam boolchamadas, por exemplo, 2 < x < 10é apenas outra maneira de escrever 2 < x and x < 10. E o andchamará bool: bool(2 < x) and bool(x < 10).

O equivalente a elementosand seria para a np.logical_andfunção, da mesma forma que você poderia usar np.logical_orcomo equivalente para or.

Para matrizes booleanas - e comparações como <, <=, ==, !=, >=e >no NumPy matrizes retornam matrizes Numpy boolean - você também pode usar os elementos-wise bit a bit funções (e operadores): np.bitwise_and( &operador)

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

e bitwise_or( |operador):

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

Uma lista completa de funções lógicas e binárias pode ser encontrada na documentação do NumPy:

MSeifert
fonte
2

se você trabalha com o pandasque resolveu o problema para mim foi que estava tentando fazer cálculos quando tinha valores de NA, a solução era executar:

df = df.dropna()

E depois disso o cálculo falhou.

Tomer Ben David
fonte
0

Essa mensagem de erro digitada também mostra enquanto if-statementé feita uma comparação onde há uma matriz e, por exemplo, um bool ou int. Veja por exemplo:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

Esta cláusula tem conjunto de dados como array e bool é euhm a "porta aberta" ... Trueou False.

Caso a função esteja agrupada em um, try-statementvocê receberá except Exception as error:a mensagem sem o tipo de erro:

O valor verdadeiro de uma matriz com mais de um elemento é ambíguo. Use a.any () ou a.all ()

ZF007
fonte
-6

tente isso => ​​numpy.array (r) ou numpy.array (sua variável) seguido pelo comando para comparar o que você desejar.

Anurag Gupta
fonte