Comment filtrer les lignes dans les pandas par regex


169

Je voudrais filtrer proprement un dataframe à l'aide de regex 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 lignes sur celles qui commencent par futiliser une expression régulière. Commencez par:

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

Ce n'est pas très utile. Cependant, cela me donnera mon index booléen:

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

Donc je pourrais alors faire ma restriction en:

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

Cela me fait mettre artificiellement un groupe dans l'expression régulière, et cela ne semble peut-être pas la voie à suivre. Y a-t-il une meilleure manière de faire cela?


5
Si vous n'êtes pas marié aux expressions régulières, foo[foo.b.str.startswith("f")]cela fonctionnera.
DSM

IMHO je pense que foo[foo.b.str.match('(f.*)').str.len() > 0]c'est une assez bonne solution! Plus personnalisable et utile que commence avec, car il contient la polyvalence de l'expression régulière.
tumultous_rooster

3
cela peut être un peu tard mais dans les nouvelles versions de pandas, le problème est résolu. la ligne foo[foo.b.str.match('f.*')]fonctionne dans pandas 0.24.2 pour moi.
Behzad Mehrtash

Réponses:


198

Utilisez contient à la place:

In [10]: df.b.str.contains('^f')
Out[10]: 
0    False
1     True
2     True
3    False
Name: b, dtype: bool

11
Comment le booléen peut-il être inversé? Trouvé: stackoverflow.com/questions/15998188/…
dmeu

4
Est-il possible d'obtenir uniquement les lignes ayant True?
shockwave

2
@shockwave, vous devriez utiliser:df.loc[df.b.str.contains('^f'), :]
Rafa

1
@shockwave Vous pouvez également simplement utiliserdf[df.b.str.contains('^f'), :]
David Jung

24

Il existe déjà une fonction de gestion des chaînes Series.str.startswith(). Tu devrais essayer foo[foo.b.str.startswith('f')].

Résultat:

    a   b
1   2   foo
2   3   fat

Je pense à ce que vous attendez.

Vous pouvez également utiliser contient avec l'option regex. Par exemple:

foo[foo.b.str.contains('oo', regex= True, na=False)]

Résultat:

    a   b
1   2   foo

na=False est d'éviter les erreurs en cas de valeurs nan, nulles, etc.


J'ai modifié ceci et cela a fonctionné pour moidf[~df.CITY.str.contains('~.*', regex= True, na=False)]
Patty Jula

Je vous remercie! c'est une excellente solution
Kedar Joshi

20

Recherche sur plusieurs colonnes avec dataframe:

frame[frame.filename.str.match('*.'+MetaData+'.*') & frame.file_path.str.match('C:\test\test.txt')]

2
frame? et 'C:\test\test.txt'? Il semble que vous répondiez à une question différente.
tumultous_rooster

le cadre est df. son lié à la même question, mais il répond comment filtrer plusieurs colonnes ('filename' et 'file_path') dans un code de ligne.
lakshman senathirajah

12

C'est peut-être un peu tard, mais c'est maintenant plus facile à faire dans Pandas. Vous pouvez appeler match with as_indexer=Truepour obtenir des résultats booléens. Ceci est documenté (avec la différence entre matchet contains) ici .


11

Merci pour l'excellente réponse @ user3136169, voici un exemple de la façon dont cela pourrait être fait en supprimant également les valeurs NoneType.

def regex_filter(val):
    if val:
        mo = re.search(regex,val)
        if mo:
            return True
        else:
            return False
    else:
        return False

df_filtered = df[df['col'].apply(regex_filter)]

Vous pouvez également ajouter regex en tant qu'arg:

def regex_filter(val,myregex):
    ...

df_filtered = df[df['col'].apply(res_regex_filter,regex=myregex)]

1
merci, à cause de cela, j'ai trouvé un moyen de filtrer une colonne par prédicat arbitraire.
jman

9

Ecrire une fonction booléenne qui vérifie l'expression régulière et utilise apply sur la colonne

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

1

Utilisation de la str tranche

foo[foo.b.str[0]=='f']
Out[18]: 
   a    b
1  2  foo
2  3  fat
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.