Comment sélectionner des lignes à partir d'un DataFrame
basé sur les valeurs d'une colonne dans Python Pandas?
En SQL, j'utiliserais:
SELECT *
FROM table
WHERE colume_name = some_value
J'ai essayé de regarder la documentation des pandas mais je n'ai pas immédiatement trouvé la réponse.
Réponses:
Pour sélectionner des lignes dont la valeur de colonne est égale à un scalaire
some_value
, utilisez==
:Pour sélectionner des lignes dont la valeur de colonne est dans un itérable
some_values
, utilisezisin
:Combinez plusieurs conditions avec
&
:Notez les parenthèses. En raison des règles de priorité des opérateurs de Python , les
&
liaisons sont plus étroites que<=
et>=
. Ainsi, les parenthèses dans le dernier exemple sont nécessaires. Sans les parenthèsesest analysé comme
qui se traduit par une valeur de vérité d'une série est une erreur ambiguë .
Pour sélectionner des lignes dont la valeur de colonne n'est pas égale
some_value
, utilisez!=
:isin
renvoie une série booléenne, donc pour sélectionner des lignes dont la valeur n'est pas danssome_values
, annulez la série booléenne en utilisant~
:Par exemple,
les rendements
Si vous avez plusieurs valeurs que vous souhaitez inclure, mettez-les dans une liste (ou plus généralement, toute itérable) et utilisez
isin
:les rendements
Notez, cependant, que si vous souhaitez effectuer cette opération plusieurs fois, il est plus efficace de créer d'abord un index, puis d'utiliser
df.loc
:les rendements
ou, pour inclure plusieurs valeurs de l'index, utilisez
df.index.isin
:les rendements
la source
df.where(condition)
, la condition doit avoir la même forme quedf
.df[df['column_name'] == some_value]
travaux, pourquoi avons-nous besoin d'ajouter.loc
ici?Il existe plusieurs façons de sélectionner des lignes dans un bloc de données pandas:
df[df['col'] == value
])df.iloc[...]
)df.xs(...)
)df.query(...)
APICi-dessous, je vous montre des exemples de chacun, avec des conseils sur l'utilisation de certaines techniques. Supposons que notre critère est la colonne
'A'
=='foo'
(Remarque sur les performances: pour chaque type de base, nous pouvons simplifier les choses en utilisant l'API pandas ou nous pouvons nous aventurer en dehors de l'API, généralement dans
numpy
, et accélérer les choses.)Configuration
La première chose dont nous aurons besoin est d'identifier une condition qui servira de critère de sélection des lignes. Nous allons commencer par le cas de l'OP
column_name == some_value
, et inclure quelques autres cas d'utilisation courants.Emprunter à @unutbu:
1. Indexation booléenne
... L'indexation booléenne nécessite de trouver la vraie valeur de la
'A'
colonne de chaque ligne égale à'foo'
, puis d'utiliser ces valeurs de vérité pour identifier les lignes à conserver. En règle générale, nous nommeriez cette série, un tableau de valeurs de vérité,mask
. Nous le ferons ici aussi.Nous pouvons ensuite utiliser ce masque pour découper ou indexer la trame de données
C'est l'un des moyens les plus simples d'accomplir cette tâche et si les performances ou l'intuitivité ne sont pas un problème, cela devrait être la méthode que vous avez choisie. Cependant, si les performances sont un problème, vous souhaiterez peut-être envisager une autre façon de créer le fichier
mask
.2. Indexation positionnelle
L'indexation positionnelle (
df.iloc[...]
) a ses cas d'utilisation, mais ce n'est pas l'un d'entre eux. Afin d'identifier où couper, nous devons d'abord effectuer la même analyse booléenne que nous avons faite ci-dessus. Cela nous laisse effectuer une étape supplémentaire pour accomplir la même tâche.3. Indexation des étiquettes
L' indexation des étiquettes peut être très pratique, mais dans ce cas, nous faisons encore plus de travail sans aucun avantage
4.
df.query()
APIpd.DataFrame.query
est un moyen très élégant / intuitif d'effectuer cette tâche, mais est souvent plus lent. Cependant , si vous faites attention aux délais ci-dessous, pour les données volumineuses, la requête est très efficace. Plus que l'approche standard et d'une ampleur similaire à ma meilleure suggestion.Ma préférence est d’utiliser le
Boolean
mask
De réelles améliorations peuvent être apportées en modifiant la façon dont nous créons notre
Boolean
mask
.mask
alternative 1Utilisez le
numpy
tableau sous-jacent et renoncez à la surcharge de création d'un autrepd.Series
Je montrerai des tests de temps plus complets à la fin, mais jetez un coup d'œil aux gains de performances que nous obtenons en utilisant l'exemple de trame de données. Tout d'abord, nous examinons la différence dans la création du
mask
L'évaluation
mask
avec lenumpy
tableau est environ 30 fois plus rapide. Cela est dû en partie au fait que l'numpy
évaluation est souvent plus rapide. Cela est également dû en partie au manque de surcharge nécessaire pour construire un index et unpd.Series
objet correspondant .Ensuite, nous examinerons le moment du découpage avec l'un
mask
par rapport à l'autre.Les gains de performances ne sont pas aussi prononcés. Nous verrons si cela résiste à des tests plus robustes.
mask
alternative 2Nous aurions pu également reconstruire la base de données. Il y a une grande mise en garde lors de la reconstruction d'une trame de données - vous devez en prendre soin
dtypes
lorsque vous le faites!Au lieu de cela,
df[mask]
nous le feronsSi la trame de données est de type mixte, ce que notre exemple est, alors lorsque nous obtenons
df.values
le tableau résultant est dedtype
object
et par conséquent, toutes les colonnes de la nouvelle trame de données seront dedtype
object
. Exigeant ainsi leastype(df.dtypes)
et tuant tous les gains de performance potentiels.Cependant, si le bloc de données n'est pas de type mixte, c'est un moyen très utile de le faire.
Donné
Contre
Nous avons réduit le temps de moitié.
mask
l'alternative 3@unutbu nous montre également comment utiliser
pd.Series.isin
pour tenir compte de chaque élément d'df['A']
être dans un ensemble de valeurs. Cela équivaut à la même chose si notre ensemble de valeurs est un ensemble d'une valeur, à savoir'foo'
. Mais il se généralise également pour inclure des ensembles de valeurs plus importants si nécessaire. Il s'avère que c'est encore assez rapide même s'il s'agit d'une solution plus générale. La seule vraie perte est dans l'intuitivité pour ceux qui ne connaissent pas le concept.Cependant, comme auparavant, nous pouvons utiliser
numpy
pour améliorer les performances tout en ne sacrifiant pratiquement rien. Nous utiliseronsnp.in1d
Calendrier
Je vais également inclure d'autres concepts mentionnés dans d'autres articles pour référence.
Code ci-dessous
Chaque colonne de ce tableau représente une trame de données de longueur différente sur laquelle nous testons chaque fonction. Chaque colonne montre le temps relatif pris, avec la fonction la plus rapide étant donné un indice de base de
1.0
.Vous remarquerez que les temps les plus rapides semblent être partagés entre
mask_with_values
etmask_with_in1d
Les fonctions
Essai
Timing spécial
En regardant le cas spécial où nous avons un seul non-objet
dtype
pour la trame de données entière. Code ci-dessousIl s'avère que la reconstruction n'en vaut pas la peine après quelques centaines de rangées.
Les fonctions
Essai
la source
.iloc(numpy.where(..))
comparer dans ce schéma? ii) vous attendriez-vous à ce que les classements soient les mêmes lorsque vous utilisez plusieurs conditions?pd.Series.isin
, notez qu'il fait usagenp.in1d
sous le capot dans un scénario spécifique, les utilisations khash dans d' autres, et applique implicitement un compromis entre le coût de hachage par rapport à la performance dans des situations spécifiques. Cette réponse a plus de détails.[{P|EXP}TIME]
- et[{C|P|EXP}SPACE]
- les coûts d'utilisation de ce qui précède les formes proposées de bloc-syntaxe (traitement de haut en bas l'ensemble dataframes à la fois) se développer , à savoir quand mis à l'échelle pour certains nombres de~1E6, ~1E9, ~1E12
lignes? Merci de nous avoir montré toute l'image, monsieur. Les lectures de référence quantitatives avec[min, Avg, MAX, StDev]
sont toujours les bienvenues, car les valeursmin
etMAX
accompagnent leMean/StDev
soulagement du lot.tl; dr
Les pandas équivalents à
est
Conditions multiples:
ou
Exemple de code
Dans le code ci-dessus, c'est la ligne
df[df.foo == 222]
qui donne les lignes en fonction de la valeur de la colonne,222
dans ce cas.Plusieurs conditions sont également possibles:
Mais à ce stade, je recommanderais d'utiliser la fonction de requête , car elle est moins détaillée et donne le même résultat:
la source
query
est la seule réponse ici compatible avec le chaînage de méthodes. Il semble que ce soit l'analogue des pandasfilter
dans dplyr.[
non de crochets(
à l'extérieur.|
c'était pour ET, mais bien sûr, c'est l'opérateur OR ...df[condition1][condition2]
df.query('`my col` == 124')
Je trouve la syntaxe des réponses précédentes redondante et difficile à retenir. Les pandas ont introduit la
query()
méthode en v0.13 et je la préfère de beaucoup. Pour votre question, vous pourriez fairedf.query('col == val')
Reproduit de http://pandas.pydata.org/pandas-docs/version/0.17.0/indexing.html#indexing-query
Vous pouvez également accéder aux variables dans l'environnement en ajoutant un
@
.la source
numexpr
installé.Plus de flexibilité
.query
avecpandas >= 0.25.0
:Réponse mise à jour d'août 2019
Puisque
pandas >= 0.25.0
nous pouvons utiliser laquery
méthode pour filtrer les trames de données avec des méthodes pandas et même des noms de colonnes qui ont des espaces. Normalement, les espaces dans les noms de colonnes donneraient une erreur, mais maintenant nous pouvons résoudre cela en utilisant un backtick (`) voir GitHub :Utilisation
.query
avec méthodestr.endswith
:Production
Nous pouvons également utiliser des variables locales en le préfixant avec un
@
dans notre requête:Production
la source
Des résultats plus rapides peuvent être obtenus en utilisant numpy.where .
Par exemple, avec la configuration d' unubtu -
Comparaisons de synchronisation:
la source
Voici un exemple simple
la source
Pour sélectionner uniquement des colonnes spécifiques parmi plusieurs colonnes pour une valeur donnée dans pandas:
Options:
ou
la source
Pour ajouter à cette fameuse question (bien qu'un peu trop tard): Vous pouvez également faire
df.groupby('column_name').get_group('column_desired_value').reset_index()
pour créer un nouveau bloc de données avec une colonne spécifiée ayant une valeur particulière. Par exempleExécutez cela donne:
la source
get_group()
retournera automatiquement une trame de données. Vous pouvez également dire "drop = True" comme paramètre dereset_index()
. En d'autres termes, il peut être raccourci comme suit:b_is_two_dataframe = df.groupby('B').get_group('two').reset_index(drop=True)
Vous pouvez également utiliser .apply:
Il fonctionne en fait ligne par ligne (c'est-à-dire qu'il applique la fonction à chaque ligne).
La sortie est
Les résultats sont les mêmes que ceux utilisés par @unutbu
la source