条件に合ったデータの行を抽出する方法です。
pandasで、列(column)の値を指定することで、データを抽出します。
抽出によってデータ数を減らすことができると、計算コストが小さくなります。
費用や時間が節約できるので、機械学習においても重要な前処理となります。
query関数を使用すると、すっきりとした条件式で抽出ができます。
サンプルデータ
説明に使用するデータを作成します。
pandas.DataFrameに、5行×3列の配列で、値を設定します。
列名 | データ型 |
val | 整数 |
name | 文字列 |
date | 日付型 |
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/1', '2019/3/1', '2019/4/1', '2019/5/1']})
# 文字列の「date]を、datetime64型に変換
df_sample['date'] = pd.to_datetime(df_sample['date'])
df_sample.head()
val name date
0 10 ABC 2019-01-01
1 20 BCD 2019-02-01
2 30 CDE 2019-03-01
3 20 EDC 2019-04-01
4 50 CBA 2019-05-01
メソッド(query())
pandas.DataFrame.query(‘条件式’, inplace=False)
query関数は、文字列の条件式でpandas.DataFrameを照会します。
デフォルトのパラメータ( inplace=False )は、データのコピーを返します。
データを変更する場合は、パラメータを設定(inplace=True)とします。
条件指定による抽出
query関数の条件式は、文字列で指定します。
<ポイント>
- 条件式は、シングルコーテーション「’」又は、ダブルコーテーション「”」で囲む
- 列名は、列名をそのまま使用(シングルコーテーション等で囲まない)
- 文字列は、 シングルコーテーション「’」又は、ダブルコーテーション「”」で囲む
ただし、条件式と別の記号を使用する(例:‘ 列名 == “文字列“ ‘) - 条件式で変数を使用するときは、変数名の前に「@」を付ける
条件式は文字列なので、「@」を付けていない変数名は、列名として評価される
比較演算子で条件指定
pandasは、True 又は False を返す式を指定して、特定の行を取得できます。
df_sample[df_sample['val'] == 20]
val name date
1 20 BCD 2019-02-01
3 20 EDC 2019-04-01
query関数を使用して同じ行を抽出します。
df_sample.query('val == 20')
val name date
1 20 BCD 2019-02-01
3 20 EDC 2019-04-01
簡潔な記述で、一致条件の抽出を行うことができました。
同じように、不一致条件で抽出します。
df_sample.query('val != 20')
val name date
0 10 ABC 2019-01-01
2 30 CDE 2019-03-01
4 50 CBA 2019-05-01
列名「name」は文字列なので、条件式の文字列内で、別の引用符で囲みます。
df_sample.query('name == "CDE"')
val name date
2 30 CDE 2019-03-01
列名「date」は日付型なので、 条件式の文字列内で、別の引用符で囲みます。
df_sample.query('date == "2019-01-01"')
val name date
0 10 ABC 2019-01-01
大小を比較する比較演算子を使用して抽出します。
df_sample.query('val >= 40')
val date name
4 50 2019-05-01 CBA
否定の条件指定
否定は、チルダ「~」ではなく、「not」を使用します。
列名「val」が、(30以上)ではないデータを抽出します。
df_sample[~(df_sample['val'] >= 30)]
val name date
0 10 ABC 2019-01-01
1 20 BCD 2019-02-01
3 20 EDC 2019-04-01
query関数を使用して同じ行を抽出します。
df_sample.query('not val >= 30')
val name date
0 10 ABC 2019-01-01
1 20 BCD 2019-02-01
3 20 EDC 2019-04-01
複数の条件指定による抽出
1つの列に対する複数の条件指定による抽出
pandasは、 True 又は False を返す複数の式を連結して、特定の行を取得できます。
df_sample[((df_sample['val'] >= 20) & (df_sample['val'] <= 40))]
val date name
1 20 2019-02-01 BCD
2 30 2019-03-01 CDE
3 20 2019-04-01 EDC
列名「val」が、(20以上)かつ(40以下)のデータを抽出しました。
コードから抽出条件が読み取りにくく、配列名「df_sample」を変更すると、3個所を書き換えることになります。
query関数を使用して同じ行を抽出します。
df_sample.query('20 <= val <= 40')
val date name
1 20 2019-02-01 BCD
2 30 2019-03-01 CDE
3 20 2019-04-01 EDC
簡潔なコードで記述できました。
一致条件は、リストを使用できます。
df_sample.query('val == [10, 30]')
val name date
0 10 ABC 2019-01-01
2 30 CDE 2019-03-01
リストの要素は、or演算子(2つ以上の条件のどれかに一致)なので、
次の式と同じ。
df_sample[((df_sample['val'] == 10) | (df_sample['val'] == 30))]
リストの要素は、文字列も使用できます。
注意する点として、クエリの条件式とは別の引用符で文字列を囲みます。
df_sample.query('name == ["ABC", "CDE"]')
val name date
0 10 ABC 2019-01-01
2 30 CDE 2019-03-01
不一致条件も、リストを使用できます。
df_sample.query('val != [10, 30]')
val name date
1 20 BCD 2019-02-01
3 20 EDC 2019-04-01
4 50 CBA 2019-05-01
リストの要素は、and演算子(2つ以上の条件のどちらにも一致)なので、
次の式と同じ。
df_sample[((df_sample['val'] != 10) & (df_sample['val'] != 30))]
複数の列に対する条件指定による抽出
pandasは、 True 又は False を返す複数の式を連結して、特定の行を取得できます。
複数の列は、それぞれ括弧で囲み、論理演算子(&、|)で連結します。
df_sample[((df_sample['val'] >= 20) & (df_sample['date'] > '2019-03-01'))]
val name date
3 20 EDC 2019-04-01
4 50 CBA 2019-05-01
列名「val」が(20以上)かつ、列名「date」が(2019-03-01より大きい)データを抽出しました。
query関数を使用して同じ行を抽出します。
df_sample.query('val >= 20 & date > "2019-03-01"')
val name date
3 20 EDC 2019-04-01
4 50 CBA 2019-05-01
条件ごとに括弧で囲む必要はありません。
囲んでもOK。
複雑な条件を設定するときは、先に処理する条件を括弧で囲むとよい。
例: (A==0 or B==1) and C>10
「かつ」は、「&」の代わりに「and」を使用できます。
「または」は、「|」の代わりに「or」を使用できます。
df_sample.query('val >= 20 and date > "2019-03-01"')
val name date
3 20 EDC 2019-04-01
4 50 CBA 2019-05-01
変数を使用した条件指定による抽出
条件式で変数を使用するときは、変数名の前に「@」を付けます。
pick_name =["ABC", "CBA"]
df_sample.query('name == @pick_name')
val name date
0 10 ABC 2019-01-01
4 50 CBA 2019-05-01
パラメータ(inplace)の設定
デフォルトでは、パラメータは( inplace=False )なので、データのコピーを返します。
元のデータを変更する場合は、パラメータを(inplace=True)とします。
サンプルデータのコピーを作成し、query関数( inplace=True )で抽出します。
df_sample_copy = df_sample.copy()
df_sample_copy.query('val == 10', inplace=True)
print(df_sample_copy)
val name date
0 10 ABC 2019-01-01
抽出前は5行だったデータが、1行になっています。
inplace=Trueだと、元のデータを変更(破壊)しますので、注意が必要です。
文字列の部分一致による抽出
文字列の「一部分と一致する」行の抽出 は、以下をご確認ください。
【Python入門】文字列の部分一致による抽出(query関数)
まとめ
- query関数を使用して、pandas.DataFrameからデータを抽出できました
- query関数で使用する条件式の記述方法がわかりました
- pandas.DataFrameで条件指定する抽出から、query関数を使った記述に書き換えができるようになりました
query関数を使用すると、簡潔に抽出条件が記述でき、 コードの可読性が高くなります。
特定の列名やデータに欠損があると、エラーになるので使いにくい場合もありますが、抽出にはquery関数を利用することをおすすめします。