正規表現でパンダの行をフィルタリングする方法


169

列の1つで正規表現を使用してデータフレームをきれいにフィルタリングしたいと思います。

不自然な例:

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

行をフィルタリングしfて、正規表現を使用して始まる行に絞り込みます。最初に行く:

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

それはそれほど有用ではありません。しかし、これは私のブールインデックスを取得します:

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

だから私はそれから私の制限をすることができました:

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

それは私が人工的にグループを正規表現に入れるようにします、そしておそらく行くのにきれいな方法ではないようです。これを行うより良い方法はありますか?


5
あなたが正規表現に慣れていない場合は、foo[foo.b.str.startswith("f")]動作します。
DSM

私見私foo[foo.b.str.match('(f.*)').str.len() > 0]はかなり良い解決策だと思います!regexの汎用性が詰め込まれているため、startswithよりもカスタマイズ可能で便利です。
tumultous_rooster 2015年

3
これは少し遅いかもしれませんが、パンダの新しいバージョンでは、問題は修正されています。ラインfoo[foo.b.str.match('f.*')]は私のためにパンダ0.24.2で動作します。
Behzad Mehrtash

回答:


198

使用が含ま代わりに:

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

11
ブール値を反転するにはどうすればよいですか?:それが見つかりstackoverflow.com/questions/15998188/...
DMEU

4
Trueを持つ行のみを取得することは可能ですか?
衝撃波2018

2
@shockwave使用する必要があります:df.loc[df.b.str.contains('^f'), :]
Rafa

1
@shockwaveまた、次のように使用することもできますdf[df.b.str.contains('^f'), :]
David Jung

23

すでに文字列処理関数がありますSeries.str.startswith()。試してみてくださいfoo[foo.b.str.startswith('f')]

結果:

    a   b
1   2   foo
2   3   fat

私はあなたが期待することを考えます。

または、contains with regexオプションを使用できます。例えば:

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

結果:

    a   b
1   2   foo

na=False nan、nullなどの値が存在する場合にエラーを防止することです


私はこれに変更し、それは私のために働きましたdf[~df.CITY.str.contains('~.*', regex= True, na=False)]
パティジュラ

ありがとうございました!これは素晴らしい解決策です
Kedar Joshi

20

データフレームを使用した複数列の検索:

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

2
frame?と'C:\test\test.txt'?別の質問に答えているようです。
tumultous_rooster

フレームはdfです。これは同じ質問に関連していますが、1行のコードで複数の列(「filename」と「file_path」)をフィルタリングする方法に答えます。
ラクシュマンsenathirajah


11

すばらしい回答@ user3136169に感謝します。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)]

また、引数として正規表現を追加することもできます。

def regex_filter(val,myregex):
    ...

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

1
おかげで、このため、任意の述語で列をフィルタリングする方法を見つけました。
jman '10

9

正規表現をチェックし、列に適用を使用するブール関数を記述します

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

1

str スライスを使用する

foo[foo.b.str[0]=='f']
Out[18]: 
   a    b
1  2  foo
2  3  fat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.