Problème de filtrage de mon image de résultat avec une condition or
. Je souhaite que mon résultat df
extrait toutes les valeurs de colonne var
supérieures à 0,25 et inférieures à -0,25.
Cette logique ci-dessous me donne une valeur de vérité ambiguë, mais cela fonctionne lorsque je divise ce filtrage en deux opérations distinctes. Que se passe-t-il ici? Je ne sais pas où utiliser la a.empty(), a.bool(), a.item(),a.any() or a.all()
suggérée.
result = result[(result['var']>0.25) or (result['var']<-0.25)]
Les instructions or
et and
python requièrent les valeurs truth
-. Pour pandas
celles-ci sont considérées comme ambiguës, vous devez donc utiliser les opérations "au niveau du bit" _|
_ (ou) ou _&
_ (et):
_result = result[(result['var']>0.25) | (result['var']<-0.25)]
_
Celles-ci sont surchargées pour que ce type d’infrastructure de données produise le résultat élémentaire or
(ou and
).
Juste pour ajouter quelques explications à cette déclaration:
L'exception est levée lorsque vous voulez obtenir le bool
d'un _pandas.Series
_:
_>>> import pandas as pd
>>> x = pd.Series([1])
>>> bool(x)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
_
Ce que vous avez frappé est un endroit où l'opérateur a implicitement converti les opérandes en bool
(vous avez utilisé or
mais cela se produit également pour and
, if
et while
):
_>>> x or x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> x and x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> if x:
... print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> while x:
... print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
_
Outre ces 4 instructions, il existe plusieurs fonctions python qui masquent certains appels bool
(comme any
, all
, filter
, ...): normalement pas problématique avec _pandas.Series
_ mais pour être complet, je voulais les mentionner.
Dans votre cas, l'exception n'est pas vraiment utile, car elle ne mentionne pas les bonnes alternatives . Pour and
et or
, vous pouvez utiliser (si vous voulez des comparaisons élément par élément):
_>>> import numpy as np
>>> np.logical_or(x, y)
_
ou simplement l'opérateur _|
_:
_>>> x | y
_
_>>> np.logical_and(x, y)
_
ou simplement l'opérateur _&
_:
_>>> x & y
_
Si vous utilisez les opérateurs, assurez-vous de définir correctement vos parenthèses à cause de priorité des opérateurs .
Il y a plusieurs fonctions logiques numériques qui devraient fonctionner sur _pandas.Series
_.
Les alternatives mentionnées dans l’exception conviennent mieux si vous l’avez rencontrée en faisant if
ou while
. J'expliquerai brièvement chacune de ces choses:
Si vous voulez vérifier si votre série est vide :
_>>> x = pd.Series([])
>>> x.empty
True
>>> x = pd.Series([1])
>>> x.empty
False
_
Python interprète normalement la len
gth des conteneurs (comme list
, Tuple
, ...) comme une valeur de vérité si elle n'a pas d'interprétation booléenne explicite. Donc, si vous voulez une vérification semblable à celle de python, vous pouvez faire: _if x.size
_ ou _if not x.empty
_ au lieu de _if x
_.
Si votre Series
contient un et un seul valeur booléenne:
_>>> x = pd.Series([100])
>>> (x > 50).bool()
True
>>> (x < 50).bool()
False
_
Si vous souhaitez vérifier le premier et unique élément de votre série (comme .bool()
mais fonctionnant même pour des contenus non booléens):
_>>> x = pd.Series([100])
>>> x.item()
100
_
Si vous voulez vérifier si tout ou un élément quelconque n'est pas nul , non vide ou non faux
_>>> x = pd.Series([0, 1, 2])
>>> x.all() # because one element is zero
False
>>> x.any() # because one (or more) elements are non-zero
True
_
Pour la logique booléenne, utilisez &
et |
.
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
>>> df
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
2 0.950088 -0.151357 -0.103219
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
>>> df.loc[(df.C > 0.25) | (df.C < -0.25)]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
Pour voir ce qui se passe, vous obtenez une colonne de booléens pour chaque comparaison, par exemple.
df.C > 0.25
0 True
1 False
2 False
3 True
4 True
Name: C, dtype: bool
Lorsque vous avez plusieurs critères, vous obtiendrez plusieurs colonnes. C'est pourquoi la logique de jointure est ambiguë. Utiliser and
ou or
traite chaque colonne séparément, vous devez donc d'abord réduire cette colonne à une seule valeur booléenne. Par exemple, pour voir si une valeur ou toutes les valeurs de chacune des colonnes sont vraies.
# Any value in either column is True?
(df.C > 0.25).any() or (df.C < -0.25).any()
True
# All values in either column is True?
(df.C > 0.25).all() or (df.C < -0.25).all()
False
Une méthode compliquée pour obtenir la même chose consiste à compresser toutes ces colonnes et à exécuter la logique appropriée.
>>> df[[any([a, b]) for a, b in Zip(df.C > 0.25, df.C < -0.25)]]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
Pour plus de détails, voir Indexation Booléenne dans la documentation.
Vous pouvez également utiliser le module Opérateur. Des informations plus détaillées sont ici Python docs
import operator
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df.loc[operator.or_(df.C > 0.25, df.C < -0.25)]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.4438
Cette excellente réponse explique très bien ce qui se passe et fournit une solution. J'aimerais ajouter une autre solution qui pourrait convenir dans des cas similaires: en utilisant la méthode query
:
result = result.query("(var > 0.25) or (var < -0.25)")
Voir aussi http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query .
(Certains tests avec une base de données avec laquelle je travaille actuellement suggèrent que cette méthode est un peu plus lente que d'utiliser les opérateurs au niveau des bits sur une série de booléens: 2 ms contre 870 µs)
Un avertissement : Au moins une situation où ce n'est pas simple, c'est quand les noms de colonnes arrivent à être des expressions python. J'avais des colonnes nommées WT_38hph_IP_2
, WT_38hph_input_2
et log2(WT_38hph_IP_2/WT_38hph_input_2)
et je voulais exécuter la requête suivante: "(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"
J'ai obtenu l'exception en cascade suivante:
KeyError: 'log2'
UndefinedVariableError: name 'log2' is not defined
ValueError: "log2" is not a supported function
Je suppose que cela s’est produit parce que l’analyseur de requête essayait de créer quelque chose à partir des deux premières colonnes au lieu d’identifier l’expression avec le nom de la troisième colonne.
Une solution de contournement possible est proposée ici .