条件に合ったデータの行を抽出する方法です。
文字列の「一部分と一致する」行の抽出は、pandasの文字列メソッドを使います。
query関数の使い方や、文字列に「完全に一致する」行の抽出は、以下をご確認ください。
【Python入門】条件指定による抽出(query関数のまとめ)
query関数を使用すると、すっきりとした条件式で抽出ができます。
サンプルデータ
説明に使用するデータを作成します。
pandas.DataFrameに、5行×4列の配列で、値を設定します。
列名 | データ型 |
val | 整数 |
name | 文字列 |
date | 日付型 |
regex | 特殊文字を含む文字列 |
import pandas as pd
df_sample = pd.DataFrame({'val': [10,20,30,20,50],
'name': ['ABC', 'BCD', 'CDE', 'EDC', 'CBA'],
'date': ['2019/1/1', '2019/2/16', '2019/3/10', '2019/3/31', '2019/5/1'],
'regex': ['test.txt', 'dog.jpg', 'Why?', '***', 'How?']})
# 文字列の「date]を、datetime64型に変換
df_sample['date'] = pd.to_datetime(df_sample['date'])
df_sample.head()
val name date regex
0 10 ABC 2019-01-01 test.txt
1 20 BCD 2019-02-16 dog.jpg
2 30 CDE 2019-03-10 Why?
3 20 EDC 2019-03-31 ***
4 50 CBA 2019-05-01 How?
文字列の部分一致による抽出
文字列の「一部分と一致する」行を抽出します。
pandasの文字列メソッドを使って、抽出の対象とする列の文字列のどの部分にある文字列と一致しているか確認します。
- 前方一致: str.startswith()
- 後方一致: str.endswith()
- 部分一致: str.contains()
- 正規表現: str.match()
正規表現は、前方一致や後方一致などの文字列を表現できる表記法です。
以下のような特殊文字を使用します。
特殊文字 | 使い方 | 備考 |
. | 任意の1文字 | |
* | 直前の文字の0回以上の繰り返し | |
^ | 文字列の先頭 | 位置指定子 |
$ | 文字列の末尾 | 位置指定子 |
前方一致(特定の文字列で始まる)
列の要素が、特定の文字列で始まる行を抽出します。
文字列メソッド: str.startswith() を使用します。
引数のengine=’python’は、デフォルトでエラーがでるときは付けてください。
df_sample.query('name.str.startswith("C")', engine='python')
val name date regex
2 30 CDE 2019-03-10 Why?
4 50 CBA 2019-05-01 How?
列名「name」が、文字列「C」で始まる行を抽出しました。
正規表現では、次のようになります。
df_sample.query('name.str.match("^C")', engine='python')
val name date regex
2 30 CDE 2019-03-10 Why?
4 50 CBA 2019-05-01 How?
文字列の最初にマッチさせるため、位置指定子「^」で文字列の先頭を指定しています。
後方一致 (特定の文字列で終わる)
列の要素が、特定の文字列で終わる行を抽出します。
文字列メソッド: str.endswith() を使用します。
df_sample.query('name.str.endswith("C")', engine='python')
val name date regex
0 10 ABC 2019-01-01 test.txt
3 20 EDC 2019-03-31 ***
列名「name」が、文字列「C」で終わる行を抽出しました。
正規表現では、次のようになります。
df_sample.query('name.str.match(".*C$")', engine='python')
val name date regex
0 10 ABC 2019-01-01 test.txt
3 20 EDC 2019-03-31 ***
文字列の最後にマッチさせるため、位置指定子「$」で文字列の末尾を指定しています。
文字列「C」の前にある「.*」は、任意の1文字「.」が、0回以上の繰り返し「*」していることを表現しています。
これは、文字列「C」の前に、任意の文字列があっても、なくてもどちらでもよいが、文字列の最後の文字が「C」であることを意味しています。
部分一致(特定の文字列を含む)
列の要素が、特定の文字列を含む行を抽出します。
文字列メソッド: str. contains() を使用します。
df_sample.query('name.str.contains("C")', engine='python')
val name date regex
0 10 ABC 2019-01-01 test.txt
1 20 BCD 2019-02-16 dog.jpg
2 30 CDE 2019-03-10 Why?
3 20 EDC 2019-03-31 ***
4 50 CBA 2019-05-01 How?
列名「name」が、文字列「C」を含む行を抽出しました。
正規表現では、次のようになります。
df_sample.query('name.str.match(".*C")', engine='python')
val name date regex
0 10 ABC 2019-01-01 test.txt
1 20 BCD 2019-02-16 dog.jpg
2 30 CDE 2019-03-10 Why?
3 20 EDC 2019-03-31 ***
4 50 CBA 2019-05-01 How?
後方一致の例から、位置指定子「$」を除いた表現となっています。
文字列「C」の前に、任意の文字列があっても、なくてもどちらでもよいが、文字列「C」が含まれていると抽出されます。
文字列「C」が含まれていた時点で抽出されるので、文字列「C」より後ろの文字列は評価していません。
正規表現で使用する特殊文字の注意点
正規表現で使用する特殊文字を指定して抽出すると、特殊文字が意味する行がされるので注意が必要です。
列名「regex」が、 特殊文字「.」を含む行を抽出してみます。
df_sample.query('regex.str.contains(".")', engine='python')
val name date regex
0 10 ABC 2019-01-01 test.txt
1 20 BCD 2019-02-16 dog.jpg
2 30 CDE 2019-03-10 Why?
3 20 EDC 2019-03-31 ***
4 50 CBA 2019-05-01 How?
列名「regex」が、特殊文字「.」が意味する「任意の1文字」を含む行が抽出されました。
文字列「.」を含む行を抽出するときは、 特殊文字をエスケープするバックスラッシュ「\」を使用します。
(バックスラッシュは、Windows環境だと円マーク「\」として表示されます。)
df_sample.query('regex.str.contains("\.")', engine='python')
val name date regex
0 10 ABC 2019-01-01 test.txt
1 20 BCD 2019-02-16 dog.jpg
列名「regex」が、文字列「.」を含む行が抽出できました。
同じように、特殊文字「?」や「*」の前に、「\」を使用すればよいです。
日付の指定による抽出
日付の一部が一致している行を抽出します。
(例: 3月、月の後半(16日以降)など)
日付の年月日などをpandasのdtアクセサで指定します。
- 年: dt.year
- 月: dt.month
- 日: dt.day
列名「date」の日付が、3月の行を抽出します。
df_sample.query('date.dt.month == 3')
val name date regex
2 30 CDE 2019-03-10 Why?
3 20 EDC 2019-03-31 ***
列名「date」の日付が、16日以降の行を抽出します。
df_sample.query('date.dt.day >= 16')
val name date regex
1 20 BCD 2019-02-16 dog.jpg
3 20 EDC 2019-03-31 ***
まとめ
- query関数を使用して、pandas.DataFrameから部分一致する行を抽出できました
- 条件式を正規表現で記述できました
- 日付の一部が一致している行を抽出できました
query関数を使用すると、簡潔に抽出条件が記述できるので、複数の条件指定をしても可読性が高いです。
完全一致と部分一致を組み合わせたり、否定との組み合わせなど、いろいろ試してみてください。