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?

justinvf
quelle
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
Wartenkuo
quelle
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

Erkan Şirin
quelle
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')]
Lakshman Senathirajah
quelle
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 .

Michael Siler
quelle
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)]
Spatz
quelle
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)]
user3136169
quelle
1

Mit str Scheibe

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