Comment sélectionner des lignes dans un DataFrame entre deux valeurs, dans Python Pandas?

99

J'essaie de modifier un DataFrame dfpour ne contenir que des lignes pour lesquelles les valeurs de la colonne closing_pricesont comprises entre 99 et 101 et j'essaie de le faire avec le code ci-dessous.

Cependant, j'obtiens l'erreur

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

et je me demande s'il existe un moyen de le faire sans utiliser de boucles.

df = df[(99 <= df['closing_price'] <= 101)]
user131983
la source
Le problème ici est que vous ne pouvez pas comparer un scalaire avec un tableau d'où l'erreur, pour les comparaisons, vous devez utiliser les opérateurs au niveau du bit et les mettre entre parenthèses en raison de la priorité des opérateurs
EdChum
df.queryet pd.evalsemblent bien adaptés à ce cas d'utilisation. Pour plus d'informations sur la pd.eval()famille de fonctions, leurs fonctionnalités et leurs cas d'utilisation, veuillez visiter Évaluation des expressions dynamiques dans les pandas à l'aide de pd.eval () .
cs95

Réponses:

103

Vous devez utiliser ()pour regrouper votre vecteur booléen pour supprimer toute ambiguïté.

df = df[(df['closing_price'] >= 99) & (df['closing_price'] <= 101)]
Jianxun Li
la source
164

Considérez également les séries entre :

df = df[df['closing_price'].between(99, 101)]
Parfait
la source
5
L'option inclusive=Trueest utilisée par défaut dans between, vous pouvez donc interroger comme cecidf = df[df['closing_price'].between(99, 101)]
Anton Ermakov
3
C'est la meilleure réponse! bon travail!
PEBKAC
Y a-t-il une fonctionnalité «pas entre» dans les pandas? Je ne le trouve pas.
dsugasa
3
@dsugasa, utilisez l' opérateur tilde avec between.
Parfait
1
@dsugasa egdf = df[~df['closing_price'].between(99, 101)]
Jan33
22

il existe une meilleure alternative - utilisez la méthode query () :

In [58]: df = pd.DataFrame({'closing_price': np.random.randint(95, 105, 10)})

In [59]: df
Out[59]:
   closing_price
0            104
1             99
2             98
3             95
4            103
5            101
6            101
7             99
8             95
9             96

In [60]: df.query('99 <= closing_price <= 101')
Out[60]:
   closing_price
1             99
5            101
6            101
7             99

UPDATE: réponse au commentaire:

J'aime la syntaxe ici mais je suis tombé en panne en essayant de combiner avec l'expression; df.query('(mean + 2 *sd) <= closing_price <=(mean + 2 *sd)')

In [161]: qry = "(closing_price.mean() - 2*closing_price.std())" +\
     ...:       " <= closing_price <= " + \
     ...:       "(closing_price.mean() + 2*closing_price.std())"
     ...:

In [162]: df.query(qry)
Out[162]:
   closing_price
0             97
1            101
2             97
3             95
4            100
5             99
6            100
7            101
8             99
9             95
MaxU
la source
J'aime la syntaxe ici mais je suis tombé en panne en essayant de combiner avec l'expression; df.query ('(mean + 2 * sd) <= closing_price <= (mean + 2 * sd)')
mapping dom
1
@mappingdom, qu'est-ce que meanet sd? Sont ces noms de colonnes?
MaxU
non, ce sont la moyenne et l'écart type calculés stockés sous forme de flottant
cartographie dom
@mappingdom, que voulez-vous dire par «stocké»?
MaxU
@mappingdom, j'ai mis à jour mon message - est-ce ce que vous demandiez?
MaxU
9

vous pouvez également utiliser la .between()méthode

emp = pd.read_csv("C:\\py\\programs\\pandas_2\\pandas\\employees.csv")

emp[emp["Salary"].between(60000, 61000)]

Production

entrez la description de l'image ici

Riz.Khan
la source
6
newdf = df.query('closing_price.mean() <= closing_price <= closing_price.std()')

ou

mean = closing_price.mean()
std = closing_price.std()

newdf = df.query('@mean <= closing_price <= @std')
crashMOGWAI
la source
3

Si vous avez affaire à plusieurs valeurs et à plusieurs entrées, vous pouvez également configurer une fonction d'application comme celle-ci. Dans ce cas, filtrer une trame de données pour les emplacements GPS qui correspondent à certaines plages.

def filter_values(lat,lon):
    if abs(lat - 33.77) < .01 and abs(lon - -118.16) < .01:
        return True
    elif abs(lat - 37.79) < .01 and abs(lon - -122.39) < .01:
        return True
    else:
        return False


df = df[df.apply(lambda x: filter_values(x['lat'],x['lon']),axis=1)]
moineau
la source
1

Au lieu de cela

df = df[(99 <= df['closing_price'] <= 101)]

Vous devriez utiliser ceci

df = df[(df['closing_price']>=99 ) & (df['closing_price']<=101)]

Nous devons utiliser les opérateurs logiques bit à bit de NumPy |, &, ~, ^ pour les requêtes composées. De plus, les parenthèses sont importantes pour la priorité des opérateurs.

Pour plus d'informations, vous pouvez visiter le lien: Comparaisons, masques et logique booléenne

Rushabh Agarwal
la source