270 votes

Comment filtrer des lignes dans pandas par regex ?

Je voudrais filtrer proprement un cadre de données en utilisant une expression rationnelle sur l'une des colonnes.

Pour un exemple artificiel :

In [210]: foo = pd.DataFrame({'a' : [1,2,3,4], 'b' : ['hi', 'foo', 'fat', 'cat']})
In [211]: foo
Out[211]: 
   a    b
0  1   hi
1  2  foo
2  3  fat
3  4  cat

Je veux filtrer les rangées sur celles qui commencent par f en utilisant une regex. Premier essai :

In [213]: foo.b.str.match('f.*')
Out[213]: 
0    []
1    ()
2    ()
3    []

Ce n'est pas terriblement utile. Cependant, cela me permettra d'obtenir mon indice booléen :

In [226]: foo.b.str.match('(f.*)').str.len() > 0
Out[226]: 
0    False
1     True
2     True
3    False
Name: b

Je pourrais alors faire ma restriction par :

In [229]: foo[foo.b.str.match('(f.*)').str.len() > 0]
Out[229]: 
   a    b
1  2  foo
2  3  fat

Mais cela m'oblige à introduire artificiellement un groupe dans l'expression rationnelle, ce qui ne semble pas être la meilleure solution. Existe-t-il une meilleure façon de procéder ?

14voto

user3136169 Points 118

Ecrire une fonction booléenne qui vérifie la regex et utiliser apply sur la colonne.

foo[foo['b'].apply(regex_function)]

7voto

Martin Bucher Points 80

En utilisant la capacité intégrée de Python à écrire des expressions lambda, nous pourrions filtrer par une opération regex arbitraire comme suit :

import re  

# with foo being our pd dataframe
foo[foo['b'].apply(lambda x: True if re.search('^f', x) else False)]

En utilisant re.search, vous pouvez filtrer par des requêtes complexes de type regex, ce qui est plus puissant à mon avis. (comme str.contains est plutôt limitée)

Il est également important de mentionner : Vous voulez que votre chaîne commencer avec un petit "f". En utilisant la regex f.* vous faites correspondre votre f à un emplacement arbitraire dans votre texte. En utilisant l'option ^ symbole vous indiquez explicitement que vous voulez qu'il soit au début de votre contenu. Ainsi, en utilisant ^f serait probablement une meilleure idée :)

2voto

W-B Points 94428

Utilisation de str tranche

foo[foo.b.str[0]=='f']
Out[18]: 
   a    b
1  2  foo
2  3  fat

1voto

rachwa Points 307

Vous pouvez utiliser query en combinaison avec contains :

foo.query('b.str.contains("^f").values')

Vous pouvez également utiliser startswith :

foo.query('b.str.startswith("f").values')

Toutefois, je préfère la première solution, car elle permet de rechercher plusieurs motifs à l'aide de la commande | opérateur.

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