So filtern Sie Zeilen in Pandas nach Regex


168

Ich möchte einen Datenrahmen mit Regex in einer der Spalten sauber filtern.

Für ein erfundenes Beispiel:

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

Ich möchte die Zeilen nach denen filtern, die mit der fVerwendung eines regulären Ausdrucks beginnen. Zuerst gehen:

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

Das ist nicht allzu nützlich. Dies bringt mir jedoch meinen booleschen Index:

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

So konnte ich meine Einschränkung tun, indem ich:

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

Das bringt mich jedoch dazu, eine Gruppe künstlich in den regulären Ausdruck zu bringen, und scheint vielleicht nicht der richtige Weg zu sein. Gibt es einen besseren Weg, dies zu tun?


5
Wenn Sie nicht mit Regexes verheiratet sind, foo[foo.b.str.startswith("f")]wird es funktionieren.
DSM

IMHO denke ich, foo[foo.b.str.match('(f.*)').str.len() > 0]ist eine ziemlich gute Lösung! Anpassbarer und nützlicher als Starts, da es die Vielseitigkeit von Regex bietet.
tumultous_rooster

3
Dies mag etwas spät sein, aber in neueren Versionen von Pandas ist das Problem behoben. Die Linie foo[foo.b.str.match('f.*')]funktioniert in Pandas 0.24.2 für mich.
Behzad Mehrtash

Antworten:


197

Verwendung enthält stattdessen:

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

11
Wie kann der Boolesche Wert invertiert werden? Gefunden: stackoverflow.com/questions/15998188/…
dmeu

4
Ist es möglich, nur die Zeilen mit True zu erhalten?
Schockwelle

2
@ Schockwave sollten Sie verwenden:df.loc[df.b.str.contains('^f'), :]
Rafa

1
@ Schockwave Auch können Sie nur verwendendf[df.b.str.contains('^f'), :]
David Jung

23

Es gibt bereits eine String-Handling-Funktion Series.str.startswith(). Du solltest es versuchen foo[foo.b.str.startswith('f')].

Ergebnis:

    a   b
1   2   foo
2   3   fat

Ich denke was du erwartest.

Alternativ können Sie die Option enthält mit Regex verwenden. Beispielsweise:

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

Ergebnis:

    a   b
1   2   foo

na=False dient dazu, Fehler zu vermeiden, falls nan-, null- usw. Werte vorliegen


Ich habe das geändert und es hat bei mir funktioniertdf[~df.CITY.str.contains('~.*', regex= True, na=False)]
Patty Jula

Danke dir! Dies ist eine großartige Lösung
Kedar Joshi

20

Mehrspaltige Suche mit Datenrahmen:

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

2
frame? und 'C:\test\test.txt'? Scheint, als würden Sie eine andere Frage beantworten.
tumultous_rooster

Rahmen ist df. Es bezieht sich auf dieselbe Frage, beantwortet jedoch, wie mehrere Spalten ('Dateiname' und 'Dateipfad') in einem Zeilencode gefiltert werden.
Lakshman Senathirajah

12

Dies mag etwas spät sein, aber in Pandas ist dies jetzt einfacher. Sie können match with aufrufen as_indexer=True, um boolesche Ergebnisse zu erhalten. Dies wird dokumentiert (zusammen mit der Differenz zwischen matchund contains) hier .


11

Vielen Dank für die großartige Antwort @ user3136169. Hier ist ein Beispiel dafür, wie dies auch beim Entfernen von NoneType-Werten erfolgen kann.

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

Sie können auch Regex als Argument hinzufügen:

def regex_filter(val,myregex):
    ...

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

1
danke, aus diesem Grund habe ich einen Weg gefunden, eine Spalte nach einem beliebigen Prädikat zu filtern.
Jman

9

Schreiben Sie eine Boolesche Funktion, die den regulären Ausdruck überprüft und auf die Spalte anwenden anwendet

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

1

Mit str Scheibe

foo[foo.b.str[0]=='f']
Out[18]: 
   a    b
1  2  foo
2  3  fat
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.