[pandas][DataFrame] 複数条件で行を抽出する方法(query, ブールインデックス)

複数条件の例(OR条件) DataFrame
複数条件の例(OR条件)
この記事は約10分で読めます。

Excelのオートフィルタ機能のように、Python in Excel でも pandas のオブジェクト DataFrame を使用したフィルタリングが可能です。この記事では、query メソッドとブールインデックス参照を使ったフィルタリング、データ抽出の記述方法について紹介します。

2023年10月現在、Python in Excel は Microsoft 365 Insider Program のベータチャネルを選択することによって使用できるベータ版のExcelでのみ利用可能です。
ベータ版のExcelのインストール・初期設定方法は以下で詳しく紹介しています。

サンプルデータ

Anaconda の公式サイトにあるサンプルデータを使用して説明します。以下のページ内の「download here」のリンクからダウンロードできます。

テーブル名が「InternetSales」、データが60,398件の売上データが入っています。

Python in Excel 入門 - query01 sampledata
サンプルデータ

構文

query メソッドの構文

DataFrame.query(expr, [inplace, kwargs])
戻り値DataFrame or None
引数説明
exprstringクエリ文字列
inplace
(任意)
bool新しいDataFrameを作成するのではなく、
DataFrameを変更するかどうか
Trueにすると戻り値はNoneになる
デフォルト:False
kwargs
(任意)
dictその他の設定を辞書型で指定

ブールインデックス参照の構文

DataFrame[List(bool) or Series]

サンプルコード

前準備

サンプルデータのブックにシートを追加し、A1セルに以下のコードを入力します。

# A1セル
# dataframeを定義
df = xl("InternetSales[#すべて]", headers = True)

抽出条件が1つ

# queryの場合
# A3セル
df1 = df.query("ProductSubcategoryName == 'Road Bikes'")

結果 8068件抽出

(A3セル)queryメソッドの例
(A3セル)queryメソッドの例
# ブールインデックスの場合
# A5セル
sr2 = df["ProductSubcategoryName"] == "Road Bikes"
# A6セル
df2 = df[sr2]
#df2 = df[df["ProductSubcategoryName"] == "Road Bikes"] # 一気に書いてもよい

結果 8068件抽出(queryメソッドの結果と同じ)

Seriesを作成
(A5セル)Series型のブールインデックスを作成
(A6セル)ブールインデックス参照の例 A3セルの結果と同じ
(A6セル)ブールインデックス参照の例 A3セルの結果と同じ

抽出する値が複数

その1(or でつなぐ)

# A8セル(queryメソッド)
df3 = df.query("ProductSubcategoryName == 'Mountain Bikes'"
           " or ProductSubcategoryName == 'Road Bikes'"
           " or ProductSubcategoryName == 'Touring Bikes'")

# A9セル(ブールインデックス)
sr4 = (df["ProductSubcategoryName"] == "Mountain Bikes") | (df["ProductSubcategoryName"] == "Road Bikes") | (df["ProductSubcategoryName"] == "Touring Bikes")
df4 = df[sr4]

結果 15205件抽出

複数条件の例(値が複数)
複数条件の例(値が複数)

その2(in句)

前述の例は or で条件を繋いでいますがやや冗長です。in 句を使うとすっきりとした記述で同じ結果を得られます。ブールインデックスの場合は isin メソッドを使用します。

# queryメソッド
df3 = df.query("ProductSubcategoryName "
               " in ['Mountain Bikes', 'Road Bikes', 'Touring Bikes']")

# ブールインデックス
sr4 = df["ProductSubcategoryName"].isin(["Mountain Bikes", "Road Bikes", "Touring Bikes"])
df4 = df[sr4]

その3(部分一致)

部分一致や前方一致、後方一致も使えるといい感じがします。

# queryメソッド
df3_1 = df.query("ProductSubcategoryName.str.contains('Bike')")   # 部分一致
df3_2 = df.query("ProductSubcategoryName.str.startswith('Bike')") # 前方一致
df3_3 = df.query("ProductSubcategoryName.str.endswith('Bikes')")  # 後方一致

# ブールインデックス
df4_1 = df[ df["ProductSubcategoryName"].str.contains('Bike') ]   # 部分一致
df4_2 = df[ df["ProductSubcategoryName"].str.startswith('Bike') ] # 前方一致
df4_3 = df[ df["ProductSubcategoryName"].str.endswith('Bikes') ]  # 後方一致

データに欠損値(NaN)が含まれる場合、上述の例ではエラーが発生します。

# 欠損値があるとエラーになる
# A1セル
df3_3 = df.query("ProductSubcategoryName.str.endswith('Bikes')")
# A2セル
df4_3 = df[ df["ProductSubcategoryName"].str.endswith('Bikes') ]
欠損値がある場合「na」引数を指定しないとエラーになる
欠損値がある場合「na」引数を指定しないとエラーになる

contains, startswith, endswith メソッドの「na」引数を指定することによってエラーを回避できます。欠損値のデータ(行)を抽出結果に含める場合は True、含めない場合は False を指定します。

# 「na」引数を指定するとエラーにならない!
# A1セル
df3_3 = df.query("ProductSubcategoryName.str.endswith('Bikes', na=False)")
# A2セル
df4_3 = df[ df["ProductSubcategoryName"].str.endswith('Bikes', na=False) ]

抽出条件の項目が複数

AND条件

# A17セル(queryメソッド)
df5 = df.query("ProductSubcategoryName.str.endswith('Bikes')"
               " and SalesAmount > 2500")

# A18セル(ブールインデックス)
sr6 = df["ProductSubcategoryName"].str.endswith('Bikes') & (df["SalesAmount"] > 2500)
df6 = df[sr6]

結果 1947件抽出

複数条件の例(AND条件)
複数条件の例(AND条件)

OR条件

# A21セル(queryメソッド)
df9 = df.query("ProductSubcategoryName == 'Road Bikes'"
               " or ProductName == 'ML Road Tire'")

# A22セル(ブールインデックス)
df10 = df[ (df["ProductSubcategoryName"] == "Road Bikes") | (df["ProductName"] == "ML Road Tire") ]

結果 8994件抽出

複数条件の例(OR条件)
複数条件の例(OR条件)

条件の否定(NOT条件)

# A24セル(queryメソッド)
df11 = df.query("not SalesAmount > 1000")

# A25セル(ブールインデックス)
df12 = df[ ~(df["SalesAmount"] > 1000) ]

結果 49050件抽出

NOT条件の例
NOT条件の例

query メソッドの TIPS

クエリ文字列内では「@」を使って変数を参照する

query メソッドのクエリ文字列に変数を指定する場合は、変数名の前に「@」を記述します。

amount = 3500
df13 = df.query("SalesAmount > @amount")
# 以下と同じ結果が得られる
#df13 = df.query("SalesAmount > 3500")

特殊な列名はバッククォート(`)で囲む

スペースや句読点 (アンダースコアを除く) を含む列名、数字で始まる列名は、バッククォート「`」で囲みます。

df14_1 = df.query("`Sales Amount` > 3000")
df14_2 = df.query("`Sales.Amount` > 3000")
df14_3 = df.query("`1_SalesAmount` > 3000")

ブールインデックスの注意点

ブールインデックス参照で条件が複数ある場合、それぞれの条件が括弧で括られていないとエラーになります。

# エラーになる例
sr7 = df["ProductSubcategoryName"] == "Jerseys" & df["SalesAmount"] > 50.0
df7 = df[sr7]

# エラーにならない例
sr7 = (df["ProductSubcategoryName"] == "Jerseys") & (df["SalesAmount"] > 50.0)
df7 = df[sr7]
ブールインデックス 括弧でくくらないとエラーになる
ブールインデックス 括弧でくくらないとエラーになる

参考

タイトルとURLをコピーしました