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)]

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)]

164

Considérez également les séries entre :

df = df[df['closing_price'].between(99, 101)]

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

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


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')

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)]

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.