ValueError: la valeur de vérité d'un tableau avec plusieurs éléments est ambiguë. Utilisez a.any () ou a.all ()

221

Je viens de découvrir un bogue logique dans mon code qui causait toutes sortes de problèmes. Je faisais par inadvertance un ET au niveau du bit au lieu d'un ET logique .

J'ai changé le code de:

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]

À ma grande surprise, j'ai reçu le message d'erreur plutôt cryptique:

ValueError: la valeur de vérité d'un tableau avec plusieurs éléments est ambiguë. Utilisez a.any () ou a.all ()

Pourquoi une erreur similaire n'a-t-elle pas été émise lorsque j'utilise une opération au niveau du bit - et comment puis-je résoudre ce problème?

Homunculus Reticulli
la source
1
Pandas propose également de la documentation à ce sujet
Greg

Réponses:

164

rest un tableau numpy (rec). Il en r["dt"] >= startdateva de même pour un tableau (booléen). Pour les tableaux numpy, l' &opération renvoie l'élément et les deux tableaux booléens.

Les développeurs de NumPy ont estimé qu'il n'y avait pas de moyen communément évalué pour évaluer un tableau dans un contexte booléen: cela pourrait signifier Truesi un élément l'est True, ou cela peut signifier Truesi tous éléments le sont True, ou Truesi le tableau a une longueur non nulle, pour n'en nommer que trois possibilités.

Étant donné que différents utilisateurs peuvent avoir des besoins et des hypothèses différents, les développeurs de NumPy ont refusé de deviner et ont plutôt décidé de déclencher une ValueError chaque fois que l'on essaie d'évaluer un tableau dans un contexte booléen. L'application andà deux tableaux numpy entraîne l'évaluation des deux tableaux dans un contexte booléen (en appelant __bool__en Python3 ou __nonzero__en Python2).

Votre code d'origine

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

semble correct. Cependant, si vous le souhaitez and, au lieu d' a and butiliser (a-b).any()ou (a-b).all().

unutbu
la source
2
Vous avez raison. Le code d'origine était correct. Le bogue semble se trouver ailleurs dans le code.
Homunculus Reticulli
2
Excellente explication. Cela implique cependant que NumPy est assez inefficace: il évalue complètement les deux tableaux booléens, tandis qu'une implémentation efficace évaluerait cond1 (i) && cond2 (i) à l'intérieur d'une seule boucle et ignorer cond2 à moins que cond1 soit vrai.
Joachim W
@JoachimWuttke: Bien que np.allet np.anysoient capables de court-circuiter, l'argument qui lui est transmis est évalué avant np.allou np.anya une chance de court-circuiter. Pour faire mieux, actuellement, vous devez écrire du code C / Cython spécialisé similaire à celui-ci .
unutbu
47

J'ai eu le même problème (c'est-à-dire l'indexation avec plusieurs conditions, ici, il s'agit de trouver des données dans une certaine plage de dates). Le (a-b).any()ou (a-b).all()ne semble pas fonctionner, du moins pour moi.

Alternativement, j'ai trouvé une autre solution qui fonctionne parfaitement pour la fonctionnalité souhaitée ( la valeur de vérité d'un tableau avec plusieurs éléments est ambiguë lorsque vous essayez d'indexer un tableau ).

Au lieu d'utiliser le code suggéré ci-dessus, simplement utiliser un numpy.logical_and(a,b)fonctionnerait. Ici, vous voudrez peut-être réécrire le code sous la forme

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

La raison de l'exception est que les andappels implicitement bool. D'abord sur l'opérande de gauche et (si l'opérande de gauche l'est True) puis sur l'opérande de droite. x and yEst donc équivalent à bool(x) and bool(y).

Cependant le boolsur un numpy.ndarray(s'il contient plus d'un élément) lèvera l'exception que vous avez vue:

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

L' bool()appel est en implicite and, mais aussi if, while, or, donc l' un des exemples suivants également échouer:

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

Il y a plus de fonctions et d'instructions en Python qui cachent les boolappels, par exemple, 2 < x < 10c'est juste une autre façon d'écrire 2 < x and x < 10. Et l' andappellera bool: bool(2 < x) and bool(x < 10).

L' équivalent élément par élément pour andserait la np.logical_andfonction, de la même manière que vous pourriez utiliser np.logical_orcomme équivalent pouror .

Pour les tableaux booléennes - et les comparaisons aiment <, <=, ==, !=, >=et >sur les tableaux NumPy renvoient des tableaux numpy booléennes - vous pouvez également utiliser les bitwise-sage élément fonctions (et opérateurs): np.bitwise_and( &opérateur)

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

et bitwise_or( |opérateur):

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

Une liste complète des fonctions logiques et binaires se trouve dans la documentation NumPy:

MSeifert
la source
2

si vous travaillez avec pandasce qui a résolu le problème pour moi, c'est que j'essayais de faire des calculs quand j'avais des valeurs NA, la solution était de lancer:

df = df.dropna()

Et après cela, le calcul a échoué.

Tomer Ben David
la source
0

Ce message d'erreur typé s'affiche également if-statementlorsqu'une comparaison est effectuée lorsqu'il existe un tableau et par exemple un booléen ou un int. Voir par exemple:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

Cette clause a un ensemble de données comme tableau et bool est euhm la "porte ouverte" ... Trueou False.

Dans le cas où la fonction est encapsulée dans un, try-statementvous recevrez except Exception as error:le message sans son type d'erreur:

La valeur de vérité d'un tableau avec plusieurs éléments est ambiguë. Utilisez a.any () ou a.all ()

ZF007
la source
-6

essayez ceci => numpy.array (r) ou numpy.array (votre variable) suivi de la commande pour comparer ce que vous souhaitez.

Anurag Gupta
la source