Je viens de découvrir un bug logique dans mon code qui causait toutes sortes de problèmes. J'effectuais par inadvertance un ET par 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 obtenu un message d'erreur plutôt cryptique :
ValueError : La valeur de vérité d'un tableau comportant plus d'un élément est ambiguë. Utilisez a.any() ou a.all().
Pourquoi une erreur similaire n'a-t-elle pas été émise lorsque j'ai utilisé une opération de type bit par bit - et comment puis-je y remédier ?
r
est un (rec)tableau numpy. Donc r["dt" ;] >= startdate
est également un tableau (booléen)
tableau. Pour les tableaux numpy, l'opération &
renvoie l'élément-et des deux tableaux booléens.
tableaux booléens.
Les développeurs de NumPy ont estimé qu'il n'y avait pas de manière commune d'évaluer un tableau dans un contexte booléen. d'évaluer un tableau dans un contexte booléen : il pouvait signifier "Vrai" si tout élément est Vrai", ou bien "Vrai" si tous les éléments sont "Vrai", ou encore "Vrai" si le tableau a une longueur non nulle, pour ne citer que trois possibilités.
Puisque des utilisateurs différents peuvent avoir des besoins différents et des hypothèses différentes, les
développeurs de NumPy ont refusé de deviner et ont décidé de lever une ValueError
lorsque l'on tente d'évaluer un tableau dans un contexte booléen. Appliquer et
à
deux tableaux numpy fait que les deux tableaux sont évalués dans un contexte booléen (en appelant
booléen (en appelant __bool__
dans Python3 ou __nonzero__
dans Python2).
Votre code original
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]
semble correct. Cependant, si vous voulez un et
, alors au lieu de a et b
, utilisez (a-b).any()
ou (a-b).all()
.
J'ai eu le même problème (c'est-à-dire l'indexation avec des conditions multiples, ici il s'agit de trouver des données dans une certaine plage de dates). Les méthodes (a-b).any()
ou (a-b).all()
ne semblent pas fonctionner, du moins pour moi.
Alternativement, j'ai trouvé une autre solution qui fonctionne parfaitement pour la fonctionnalité que je souhaite (https://stackoverflow.com/questions/12647471/the-truth-value-of-an-array-with-more-than-one-element-is-ambigous-when-trying-t).
Au lieu d'utiliser le code suggéré ci-dessus, utiliser simplement un numpy.logical_and(a,b)
fonctionnerait. Ici, vous pouvez réécrire le code comme suit
selected = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]
La raison de cette exception est que and
appelle implicitement bool
. D'abord sur l'opérande de gauche et (si l'opérande de gauche est True
) ensuite sur l'opérande de droite. Donc x et y
est équivalent à bool(x) et bool(y)
.
Cependant, le bool
sur un numpy.ndarray
(s'il contient plus d'un élément) lancera 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'appel à bool()
est implicite dans and
, mais aussi dans if
, while
, or
, donc n'importe lequel des exemples suivants échouera également :
>>> 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 des appels bool
, par exemple 2 < x < 10
est juste une autre façon d'écrire 2 < x et x < 10
. Et le et
appellera bool
: bool(2 < x) et bool(x < 10)
.
L'équivalent selon les éléments de et
serait la fonction np.logical_and
, de même vous pourriez utiliser np.logical_or
comme équivalent de ou
.
Pour les tableaux booléens - et les comparaisons comme <
, <=
, ==
, !=
, >=
et >
sur des tableaux NumPy retournant des tableaux NumPy booléens - vous pouvez également utiliser les fonctions (et opérateurs) element-wise bitwise : 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 de NumPy :