query()メソッド
query()で読みやすいフィルタ式を文字列として記述し、@を使ってクエリ内でPython変数を参照し、フィルタを連結します。
「query()メソッド」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
query()を使う理由
Pandasのブールインデックスは強力ですが、多くの条件を組み合わせると冗長になることがあります。query()メソッドを使うと、フィルター式を通常の文字列として記述できるため、多くの人にとって読みやすくなります。特にSQLの経験がある人にはわかりやすい書き方です。df[(df['age'] > 30) & (df['salary'] > 50000)]と書く代わりに、df.query('age > 30 and salary > 50000')と記述できます。
クエリ文字列はDataFrameの列名を基準に評価されるため、文字列の中では列名が変数名のように扱われます。
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 35, 28, 45],
'salary': [50000, 90000, 70000, 120000]
})
# Boolean indexing style
result1 = df[(df['age'] > 27) & (df['salary'] > 60000)]
# Equivalent query() style
result2 = df.query('age > 27 and salary > 60000')
print(result2)
# name age salary
# 1 Bob 35 90000
# 2 Carol 28 70000クエリ文字列内の構文規則
クエリ文字列内では、標準的なPythonの比較演算子(>、<、==、!=、>=、<=)と、論理演算子and、or、notを使用できます。通常のブールインデックスとは異なり、ここでは英単語を使えるため、アンパサンドやパイプは必要ありません。
空白を含む列名やPythonのキーワードと競合する列名は、バッククォートで囲む必要があります。df.query('`first name` == "Alice"')のように記述します。
import pandas as pd
df = pd.DataFrame({
'product': ['A', 'B', 'C', 'D'],
'price': [10, 200, 50, 300],
'in_stock': [True, False, True, True]
})
# Use 'and', 'or', 'not' in query strings
result = df.query('price > 40 and in_stock == True')
print(result)
# product price in_stock
# 2 C 50 True
# 3 D 300 True@を使ったPython変数の参照
query()の重要な機能の1つは、@接頭辞を使って、周囲のスコープにあるPython変数を参照できることです。これにより、フィルターのパラメーター化が簡単になります。しきい値を計算して変数に格納し、値をハードコードする代わりに、クエリ文字列内で@variable_nameを使用します。
このパターンは、実行時にフィルター引数を受け取る関数で特に便利です。
import pandas as pd
df = pd.DataFrame({
'city': ['NYC', 'LA', 'Chicago', 'Houston'],
'population': [8336817, 3979576, 2693976, 2320268]
})
min_pop = 3_000_000 # Python variable
# Use @ to inject the variable into the query
result = df.query('population > @min_pop')
print(result)
# city population
# 0 NYC 8336817
# 1 LA 3979576query()呼び出しの連結
query()は新しいDataFrameを返すため、複数のquery呼び出しを連結したり、他のPandasメソッドとパイプラインで組み合わせたりできます。連結すると、各フィルタリング処理をそれぞれ1行に記述できるため、ロジックの読み取り、デバッグ、変更が簡単になります。
.groupby()、.sort_values()、.head()などのメソッドをquery()と連結して、簡潔な分析パイプラインを構築することもできます。
import pandas as pd
df = pd.DataFrame({
'region': ['North', 'South', 'North', 'East', 'South'],
'year': [2022, 2022, 2023, 2023, 2023],
'revenue': [100, 200, 150, 80, 300]
})
# Chain two query calls
result = (df
.query('year == 2023')
.query('revenue > 100')
.sort_values('revenue', ascending=False)
)
print(result)
# region year revenue
# 4 South 2023 300
# 2 North 2023 150query()とブールインデックスの比較
どちらの方法でも同じ結果を得られますが、それぞれ適した場面があります。query()は、ブールインデックスでは多くの括弧が必要になる複数条件のフィルターに適しています。一方、query文字列ではサポートされないメソッド呼び出しのような、複雑なPython式を条件に含める場合は、ブールインデックスのほうが適しています。
ほとんどの場合、パフォーマンスは同程度です。ただし、query()は内部でnumexprライブラリを使用するため、非常に大きなDataFrameでは少し高速になることがあります。
import pandas as pd
df = pd.DataFrame({
'A': range(10),
'B': range(10, 20)
})
# Boolean indexing
result_bool = df[(df['A'] > 2) & (df['B'] < 18) & (df['A'] != 5)]
# Equivalent query — much more readable
result_query = df.query('A > 2 and B < 18 and A != 5')
print(result_query)
# A B
# 3 3 13
# 4 4 14
# 6 6 16
# 7 7 17query()での文字列比較
クエリ文字列内で文字列リテラルを引用符で囲むと、文字列列の値を対象にフィルタリングできます。外側のクエリ文字列にダブルクォート、文字列値にシングルクォートを使うか、その逆にします。ただし、組み合わせは一貫させてください。query()はcontains()のような.strメソッドをサポートしていないため、その場合は.strを使ったブールインデックスを使用します。
import pandas as pd
df = pd.DataFrame({
'country': ['USA', 'UK', 'Canada', 'USA', 'Germany'],
'sales': [400, 150, 200, 600, 300]
})
# Single quotes for the string value inside double-quoted query
result = df.query('country == "USA"')
print(result)
# country sales
# 0 USA 400
# 3 USA 600in演算子とnot in演算子の使用
クエリ文字列内では、Pythonのリストと同様に、メンバーシップテスト用のin演算子とnot in演算子を使用できます。これは、複数の==条件をorで連結するよりもすっきりした方法です。値のリストはクエリ文字列に直接記述します。
import pandas as pd
df = pd.DataFrame({
'status': ['active', 'inactive', 'pending', 'active', 'closed'],
'amount': [100, 200, 50, 300, 150]
})
# Keep rows where status is in a specific list
result = df.query('status in ["active", "pending"]')
print(result)
# status amount
# 0 active 100
# 2 pending 50
# 3 active 300
# Exclude certain statuses
excluded = df.query('status not in ["closed", "inactive"]')
print(excluded.shape) # (3, 2)query()による数値範囲フィルター
10 < price < 500のようなPythonの連鎖比較はクエリ文字列内で使用できるため、範囲フィルターを表現力豊かに記述できます。標準的なブールインデックスでは、between()を使うか、2つの条件を&で結合しなければ同じことはできません。
import pandas as pd
df = pd.DataFrame({
'product': ['A', 'B', 'C', 'D', 'E'],
'price': [5, 50, 150, 300, 500]
})
# Chained comparison — only works inside query()
result = df.query('50 <= price <= 300')
print(result)
# product price
# 1 B 50
# 2 C 150
# 3 D 300query()の制限
query()は強力ですが、いくつか制限があります。空白や特殊文字を含む列名には、バッククォートによる引用が必要です。カスタム関数や複数行のロジックなど、非常に複雑なPython式は文字列内でサポートされません。また、列名がclassやifのようなPythonのキーワードと競合すると、query()が予期しない結果を返すことがあります。この場合もバッククォートで囲んでください。
query()で明確に表現できない処理には、標準的なブールインデックスを使用してください。
import pandas as pd
df = pd.DataFrame({'first name': ['Alice', 'Bob'], 'class': [1, 2]})
# Backtick-quote column names with spaces or reserved words
result = df.query('`first name` == "Alice" and `class` == 1')
print(result)
# first name class
# 0 Alice 1実践例:注文のフィルタリング
ここでは、query()と変数参照を組み合わせ、さらにgroupbyへ連結する実践例を示します。まずフィルタリングしてから集計するこのパターンでは、不要な行を処理せずに済むため、コードが明確になるだけでなく、大規模なデータセットでは処理も高速になります。
import pandas as pd
orders = pd.DataFrame({
'region': ['East', 'West', 'East', 'West', 'East'],
'year': [2023, 2023, 2024, 2024, 2024],
'revenue': [100, 200, 300, 400, 500]
})
min_year = 2024
# Filter to recent orders in the East region, then sum revenue
summary = (
orders
.query('year >= @min_year and region == "East"')
.groupby('region')['revenue'].sum()
)
print(summary)
# region
# East 800
# Name: revenue, dtype: int64query()とメソッド連結のベストプラクティス
メソッドチェーン内でquery()を使用することは、現代的なPandasコードにおけるベストプラクティスです。変換パイプラインの各ステップが明確になり、コード自体が処理内容を説明する形になります。チェーン全体を括弧で囲むと、バックスラッシュを使わずに複数行へ分割できます。
assign()で列を追加し、groupby()で集計し、pipe()でカスタム関数を適用するなど、query()と組み合わせて読みやすいパイプラインを構築できます。
import pandas as pd
df = pd.DataFrame({
'dept': ['Eng', 'HR', 'Eng', 'Sales', 'HR'],
'salary': [90000, 50000, 120000, 70000, 55000],
'years': [3, 5, 8, 2, 4]
})
result = (
df
.query('years > 2 and dept != "HR"')
.assign(bonus=lambda x: x['salary'] * 0.1)
.sort_values('salary', ascending=False)
)
print(result[['dept', 'salary', 'bonus']])
# dept salary bonus
# 2 Eng 120000 12000.0
# 0 Eng 90000 9000.0理解度チェック
query()メソッドの理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、query()はフィルター式を文字列として受け取るため、複数条件のフィルターを読みやすく記述できること、@variable_nameでPython変数をクエリに組み込めること、そして標準的なブールインデックスでは使えないin/not inや連鎖比較を使用できることを学びました。次は、メンバーシップや範囲のフィルターを簡潔に記述するisin()とbetween()について学びます。
よくある質問
「query()メソッド」レッスンは無料ですか?
はい。「query()メソッド」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
「query()メソッド」で何を学びますか?
query()で読みやすいフィルタ式を文字列として記述し、@を使ってクエリ内でPython変数を参照し、フィルタを連結します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Pandas & NumPy Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「query()メソッド」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPandas & NumPy Academyレッスンでコードを書いて実行できますか?
はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。