Je ne parviens pas à évaluer les valeurs d'un dictionnaire à l'aide d'instructions if.
Étant donné le dictionnaire suivant, que j’ai importé à partir d’une base de données (au cas où cela compte):
>>> pnl[company]
29: Active Credit Date Debit Strike Type
0 1 0 2013-01-08 2.3265 21.15 Put
1 0 0 2012-11-26 40 80 Put
2 0 0 2012-11-26 400 80 Put
J'ai essayé d'évaluer la déclaration suivante pour établir la valeur de la dernière valeur de Active
:
if pnl[company].tail(1)['Active']==1:
print 'yay'
Cependant, j'ai été confronté au message d'erreur suivant:
Traceback (most recent call last):
File "<pyshell#69>", line 1, in <module>
if pnl[company].tail(1)['Active']==1:
File "/usr/lib/python2.7/dist-packages/pandas/core/generic.py", line 676, in __nonzero__
.format(self.__class__.__name__))
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Cela m'a surpris, étant donné que je pouvais afficher la valeur souhaitée à l'aide de la commande ci-dessus sans l'instruction if:
>>> pnl[company].tail(1)['Active']
30: 2 0
Name: Active, dtype: object
Étant donné que la valeur est clairement égale à zéro et que l'indice est égal à 2, j'ai essayé ce qui suit pour un bref contrôle de cohérence et constaté que les choses ne se passaient pas comme prévu.
>>> if pnl[company]['Active'][2]==0:
... print 'woo-hoo'
... else:
... print 'doh'
doh
Ma question est:
1) Que peut-il se passer ici? Je soupçonne que je comprends mal les dictionnaires à un niveau fondamental.
2) J'ai remarqué que lorsque j'évoque une valeur donnée de ce dictionnaire, le nombre à gauche augmente de 1. Qu'est-ce que cela représente? Par exemple:
>>> pnl[company].tail(1)['Active']
31: 2 0
Name: Active, dtype: object
>>> pnl[company].tail(1)['Active']
32: 2 0
Name: Active, dtype: object
>>> pnl[company].tail(1)['Active']
33: 2 0
Name: Active, dtype: object
>>> pnl[company].tail(1)['Active']
34: 2 0
Name: Active, dtype: object
Merci d'avance pour votre aide.
Ce que vous cédez est un objet de la série Pandas et il ne peut pas être évalué comme vous le tentez même s'il ne s'agit que d'une valeur unique pour laquelle vous devez modifier votre ligne:
if pnl[company].tail(1)['Active'].any()==1:
print 'yay'
En ce qui concerne votre deuxième question, voyez mon commentaire.
MODIFIER
À partir des commentaires et du lien vers votre sortie, l'appel de any()
a corrigé le message d'erreur, mais vos données sont en fait des chaînes. La comparaison a donc échoué. Vous pouvez soit:
if pnl[company].tail(1)['Active'].any()=='1':
print 'yay'
Effectuer une comparaison de chaîne ou corriger les données quelle que soit leur lecture ou leur génération.
Ou faire:
pnl['Company']['Active'] = pnl['Company']['Active'].astype(int)
Pour convertir la dtype
de la colonne afin que votre comparaison soit plus correcte.
Une série est une sous-classe de NDFrame. La méthode NDFrame.__bool__
déclenche toujours une ValueError . Ainsi, essayer d'évaluer une série dans un contexte booléen génère une valeur ValueError, même si la série n'a qu'une seule valeur.
La raison pour laquelle les cadres NDF n'ont pas de valeur booléenne (err, c'est-à-dire, toujours déclencher une valeur ValueError), est parce qu'il existe plus d'un critère possible auquel on peut raisonnablement s'attendre pour qu'un cadre NDF soit vrai. Cela pourrait signifier
.all()
)Series.any()
).empty()
)Étant donné que l’un ou l’autre est possible et que différents utilisateurs ont des attentes différentes, au lieu de choisir un choix, les développeurs refusent de deviner et demandent à l’utilisateur du NDFrame de préciser le critère qu’ils souhaitent utiliser.
Le message d'erreur répertorie les choix les plus probables:
Utilisez a.empty, a.bool (), a.item (), a.any () ou a.all ()
Puisque dans votre cas, vous savez que la série ne contiendra qu'une seule valeur, vous pouvez utiliser item
:
if pnl[company].tail(1)['Active'].item() == 1:
print 'yay'
En ce qui concerne votre deuxième question: les nombres sur la gauche semblent être des numéros de ligne produits par votre interprète Python (PyShell?) - mais ce n’est que ma supposition.
ATTENTION: Vraisemblablement,
if pnl[company].tail(1)['Active']==1:
signifie que vous souhaitez que la condition soit vraie lorsque la valeur unique de la série est égale à 1. Le code
if pnl[company].tail(1)['Active'].any()==1:
print 'yay'
sera True si le type de la série est numérique et que la valeur de la série est tout nombre autre que 0. Par exemple, si nous prenons pnl[company].tail(1)['Active']
égal à
In [128]: s = pd.Series([2], index=[2])
puis
In [129]: s.any()
Out[129]: True
et donc,
In [130]: s.any()==1
Out[130]: True
Je pense que s.item() == 1
préserve plus fidèlement le sens voulu:
In [132]: s.item()==1
Out[132]: False
(s == 1).any()
fonctionnerait aussi, mais utiliser any
n'exprime pas votre intention très clairement, car vous savez que la série ne contiendra qu'une seule valeur.
Votre question n'a rien à voir avec les dictionnaires Python, ni avec le Python natif . Il s'agit de pandas Series, et les autres réponses vous ont donné la syntaxe correcte:
Pour interpréter vos questions dans un sens plus large, il s’agit de savoir comment pandas Series
a été lancé sur NumPy
, et Historiquement, jusqu'à récemment, NumPy supportait notoirement peu les valeurs logiques et les opérateurs . pandas fait le meilleur travail possible avec ce que NumPy fournit. Avoir à invoquer parfois manuellement des fonctions logiques numpy au lieu d'écrire du code avec des opérateurs arbitraires (Python) est ennuyeux et maladroit, et enfle parfois le code des pandas. En outre, vous devez souvent faire cela pour la performance (numpy mieux que de penser à Python natif). Mais c'est le prix que nous payons.
Il existe de nombreuses limitations, bizarreries et pièges (exemples ci-dessous) - le meilleur conseil est de se méfier des booléens en tant que citoyen de première classe dans les pandas en raison des limitations de numpy:
pandas Mises en garde et pièges - Utiliser des énoncés de vérité/avec des pandas
un exemple de performance: Python ~ peut être utilisé à la place de np.invert () - plus lisible mais 3x plus lent ou pire
quelques pièges et limitations: dans le code ci-dessous, notez que numpy récent autorise désormais les valeurs booléennes (représentées en interne par int) et autorise les NA, mais que, par exemple, value_counts()
ignore les NA (comparer au tableau de R, qui a l'option 'useNA' ).
.
import numpy as np
import pandas as pd
s = pd.Series([True, True, False, True, np.NaN])
s2 = pd.Series([True, True, False, True, np.NaN])
dir(s) # look at .all, .any, .bool, .eq, .equals, .invert, .isnull, .value_counts() ...
s.astype(bool) # WRONG: should use the member s.bool ; no parentheses, it's a member, not a function
# 0 True
# 1 True
# 2 False
# 3 True
# 4 True # <--- should be NA!!
#dtype: bool
s.bool
# <bound method Series.bool of
# 0 True
# 1 True
# 2 False
# 3 True
# 4 NaN
# dtype: object>
# Limitation: value_counts() currently excludes NAs
s.value_counts()
# True 3
# False 1
# dtype: int64
help(s.value_counts) # "... Excludes NA values(!)"
# Equality comparison - vector - fails on NAs, again there's no NA-handling option):
s == s2 # or equivalently, s.eq(s2)
# 0 True
# 1 True
# 2 True
# 3 True
# 4 False # BUG/LIMITATION: we should be able to choose NA==NA
# dtype: bool
# ...but the scalar equality comparison says they are equal!!
s.equals(s2)
# True