Je viens de découvrir un bogue logique dans mon code qui causait toutes sortes de problèmes. Je faisais par inadvertance un au niveau du bit AND au lieu d'un AND 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 comportant 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 des bits - et comment puis-je résoudre ce problème?
r
est un tableau numpy (rec). Donc, r["dt"] >= startdate
est également un tableau (booléen). Pour les tableaux numpy, l'opération &
renvoie le tableau élément par élément et les deux tableaux booléens.
Les développeurs de NumPy ont estimé qu'il n'existait aucune méthode couramment comprise pour évaluer un tableau dans un contexte booléen: cela pourrait signifier True
si tout élément est True
, ou cela pourrait signifier True
if all les éléments sont True
ou True
si le tableau a une longueur non nulle, pour ne nommer que trois possibilités.
Étant donné que différents utilisateurs peuvent avoir des besoins différents et des hypothèses différentes, les développeurs de NumPy ont refusé de deviner et ont plutôt décidé de générer une valeur ValueError chaque fois que l'on tente d'évaluer un tableau dans un contexte booléen. L'application de and
à deux tableaux numpy entraîne l'évaluation de ces 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. Toutefois, si vous voulez and
, utilisez a and b
ou (a-b).any()
au lieu de (a-b).all()
.
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 période). 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 plus d'un élément est ambigu lors d'une tentative d'indexation d'un tablea ).
Plutôt que d'utiliser le code suggéré ci-dessus, il vous suffira d'utiliser numpy.logical_and(a,b)
. Ici, vous voudrez peut-être réécrire le code comme
selected = r(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 gauche et (si l'opérande gauche est True
), puis sur l'opérande droit. Donc, x and y
est équivalent à bool(x) and bool(y)
.
Cependant, la bool
d'un numpy.ndarray
(s'il contient plus d'un élément) lève 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
, de sorte que l'un 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 dans Python qui cachent les appels bool
, par exemple 2 < x < 10
est simplement une autre façon d'écrire 2 < x and x < 10
. Et la and
appellera bool
: bool(2 < x) and bool(x < 10)
.
Le element-wise équivalent pour and
serait le np.logical_and
, de même, vous pourriez utiliser np.logical_or
comme équivalent. pour or
.
Pour les tableaux booléens - et les comparaisons telles que <
, <=
, ==
, !=
, >=
et >
sur les tableaux NumPy renvoient des tableaux booléens NumPy - vous pouvez également utiliser les fonctions element-wise bitwise (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 est disponible dans la documentation de NumPy:
si vous travaillez avec pandas
ce qui me permettait de résoudre le problème, c’était que j’essayais de faire des calculs lorsque j’avais les valeurs NA, la solution consistait à exécuter:
df = df.dropna()
Et après cela, le calcul a échoué.