0Pricing
Pandas & NumPy Academy · Lesson

The query() Method

Write readable filter expressions as strings with query(), use Python variables inside queries with @, and chain filters.

The query() Method is a free Pandas & NumPy Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Pandas & NumPy Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Use query()?

Pandas boolean indexing is powerful but can become verbose when combining many conditions. The query() method lets you write filter expressions as plain strings, which many people find more readable — especially those coming from a SQL background. Instead of df[(df['age'] > 30) & (df['salary'] > 50000)], you write df.query('age > 30 and salary > 50000').

The query string is evaluated against the column names of the DataFrame, so column names act like variable names inside the string.

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

Syntax Rules Inside a Query String

Inside a query string you can use standard Python comparison operators (>, <, ==, !=, >=, <=) and logical connectors and, or, not. Unlike regular boolean indexing, you can use the English words here — no ampersands or pipes needed.

Column names with spaces or that clash with Python keywords must be wrapped in backticks: 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

Referencing Python Variables with @

A key feature of query() is the ability to reference Python variables from the surrounding scope using the @ prefix. This makes it easy to parameterise filters: compute a threshold, store it in a variable, then use @variable_name inside the query string instead of hardcoding the value.

This pattern is very useful in functions that accept filter arguments at runtime.

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     3979576

Chaining query() Calls

Because query() returns a new DataFrame, you can chain multiple query calls or combine them with other Pandas methods in a pipeline. Chaining keeps each filtering step on its own line, making the logic easy to read, debug, and modify.

You can also chain query() with methods like .groupby(), .sort_values(), or .head() to build concise analysis pipelines.

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      150

Comparing query() to Boolean Indexing

Both methods produce the same result, but each has its place. query() excels at multi-condition filters that would require many parentheses with boolean indexing. Boolean indexing is better when your condition involves complex Python expressions like method calls that are not supported in query strings.

Performance is similar for most cases; query() can be slightly faster on very large DataFrames because it uses the numexpr library under the hood.

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  17

String Comparisons in query()

You can filter on string column values inside a query string by quoting the string literal. Use double quotes for the outer query string and single quotes for the string value, or vice versa — just be consistent. Note that query() does not support .str methods like contains(); for those, use boolean indexing with .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    600

Using in and not in Operators

Inside query strings, Pandas supports the in and not in operators for membership tests, similar to Python lists. This is a clean alternative to chaining multiple == conditions with or. The list of values is written directly in the query string.

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)

Numeric Range Filters with query()

Python's chained comparisons like 10 < price < 500 work inside query strings, making range filters very expressive. This is not possible with standard boolean indexing without using between() or two separate conditions combined with &.

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    300

Limitations of query()

query() is powerful but has a few limitations. Column names with spaces or special characters need backtick quoting. Very complex Python expressions (custom functions, multi-line logic) are not supported inside the string. Also, query() may produce unexpected results if column names clash with Python keywords like class or if — backtick-quote those too.

For anything that query() cannot express cleanly, fall back to standard boolean indexing.

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

Practical Example: Filtering Orders

Here is a practical demonstration combining query() with a variable reference and chaining to a groupby. This pattern — filter first, then aggregate — avoids processing rows you don't need, which is both clearer and faster on large datasets.

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: int64

query() and Method Chaining Best Practices

Using query() inside a method chain is a best practice in modern Pandas code. It makes each step of the transformation pipeline clear and self-documenting. Wrap the entire chain in parentheses so you can break it across multiple lines without backslashes.

Combine query() with assign() for adding columns, groupby() for aggregations, and pipe() for custom functions to build fully readable pipelines.

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

Quick Check

Test your understanding of the query() method.

Lesson Recap

In this lesson you learned: query() accepts filter expressions as strings making multi-condition filters more readable, @variable_name injects Python variables into the query, and you can use in/not in and chained comparisons that are not possible with standard boolean indexing. Next up we explore isin() and between() for concise membership and range filters.

Frequently asked questions

Is the “The query() Method” lesson free?

Yes — the full text of “The query() Method” is free to read here on the web, and the Pandas & NumPy Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Pandas & NumPy Academy course, upgrade to CoddyKit PRO.

What will I learn in “The query() Method”?

Write readable filter expressions as strings with query(), use Python variables inside queries with @, and chain filters. You practise Pandas & NumPy Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Pandas & NumPy Academy?

No prior experience is required. Pandas & NumPy Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “The query() Method” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Pandas & NumPy Academy lesson?

Yes. Every Pandas & NumPy Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Boolean Indexing on DataFrames
  2. The query() Method
  3. isin() and between() Filters
  4. Selecting Columns by Pattern
← Back to Pandas & NumPy Academy