681 votes

La valeur de vérité d'une série est ambiguë. Utilisez a.empty, a.bool(), a.item(), a.any() ou a.all().

J'ai du mal à filtrer mon cadre de données de résultats avec un filtre de type or condition. Je veux que mon résultat df pour extraire toutes les colonnes var qui sont supérieures à 0,25 et inférieures à -0,25.

La logique ci-dessous me donne une valeur de vérité ambiguë, mais elle fonctionne lorsque je divise ce filtrage en deux opérations distinctes. Que se passe-t-il ici ? Je ne suis pas sûr de l'endroit où il faut utiliser la méthode suggérée. a.empty(), a.bool(), a.item(),a.any() or a.all() .

result = result[(result['var'] > 0.25) or (result['var'] < -0.25)]

90 votes

Utiliser | au lieu de or

4 votes

Voici une solution de contournement : abs(result['var'])>0.25

5 votes

907voto

MSeifert Points 6307

Le site or et and les déclarations python exigent truth -valeurs. Pour pandas Ces termes sont considérés comme ambigus, vous devez donc utiliser "bitwise". | (ou) ou & (et) des opérations :

result = result[(result['var']>0.25) | (result['var']<-0.25)]

Ceux-ci sont surchargés pour ce type de structures de données afin de produire la méthode par éléments. or (ou and ).


Juste pour ajouter quelques explications supplémentaires à cette déclaration :

L'exception est levée lorsque l'on veut obtenir l'adresse de l'utilisateur. 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 trouvé, c'est un endroit où l'opérateur implicitement a converti les opérandes en bool (vous avez utilisé or mais cela arrive aussi 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().

En plus de ces 4 déclarations, il y a plusieurs fonctions python qui cachent quelques bool (comme any , all , filter ...) qui ne posent normalement pas de problèmes avec pandas.Series mais par souci d'exhaustivité, je tenais à les mentionner.


Dans votre cas, l'exception n'est pas vraiment utile, parce qu'elle ne mentionne pas la bonnes alternatives . Pour and et or que vous pouvez utiliser (si vous voulez des comparaisons par éléments) :

  • numpy.logical_or :

    >>> import numpy as np
    >>> np.logical_or(x, y)

    ou simplement le | opérateur :

    >>> x | y
  • numpy.logical_and :

    >>> np.logical_and(x, y)

    ou simplement le & opérateur :

    >>> x & y

Si vous utilisez les opérateurs, assurez-vous de placer vos parenthèses correctement, en raison de la préséance de l'opérateur .

Il y a plusieurs fonctions logiques numpy dont devrait travailler sur pandas.Series .


Les alternatives mentionnées dans l'Exception sont plus adaptées si vous avez rencontré ce problème en faisant if ou while . Je vais brièvement expliquer chacun d'entre eux :

  • 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 l'option len gth des conteneurs (comme list , tuple ...) comme valeur de vérité si elle n'a pas d'interprétation booléenne explicite. Donc, si vous voulez la vérification de type python, vous pouvez faire : if x.size ou if not x.empty au lieu de if x .

  • Si votre Series contient le seul et unique valeur booléenne :

    >>> x = pd.Series([100])
    >>> (x > 50).bool()
    True
    >>> (x < 50).bool()
    False
  • Si vous voulez vérifier le premier et seul élément de votre série (comme .bool() mais fonctionne même pour les contenus non booléens) :

    >>> x = pd.Series([100])
    >>> x.item()
    100
  • Si vous voulez vérifier si tous ou tout L'élément n'est pas nul, pas vide ou pas 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

89voto

Nipun Points 81

Eh bien, les pandas utilisent le bitwise & | et chaque condition doit être enveloppée dans un ()

Par exemple, les travaux suivants

data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]

Mais la même requête sans les parenthèses appropriées n'est pas

data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]

1 votes

Vous avez tout à fait raison ! Merci.

57voto

Alexander Points 49390

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 ex.

df.C > 0.25
0     True
1    False
2    False
3     True
4     True
Name: C, dtype: bool

Si vous avez plusieurs critères, vous obtiendrez plusieurs colonnes. C'est pourquoi la logique de jointure est ambiguë. Utilisation de 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 façon alambiquée d'obtenir la même chose est de regrouper toutes ces colonnes et d'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, reportez-vous à Indexation booléenne dans les docs.

12voto

Ou, alternativement, vous pouvez utiliser le module Operator. Des informations plus détaillées sont disponibles ici Documentation Python

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

4voto

bli Points 2369

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 : l'utilisation de la fonction query méthode :

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 effectués avec un cadre de données sur lequel je travaille actuellement suggèrent que cette méthode est un peu plus lente que l'utilisation des opérateurs de type bitwise sur des séries de booléens : 2 ms contre 870 µs).

Un avertissement : Au moins une situation où cela n'est pas simple est lorsque les noms de colonnes se trouvent ê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 effectuer la requête suivante : "(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"

J'ai obtenu la cascade d'exceptions 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êtes a essayé de faire 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 est proposée ici .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X