Filtering with query() & eval()
df.query() filters rows using a plain-English string expression — like "age > 30 and city == 'NYC'" — instead of stacking bracketed boolean masks.
Learn Filtering with query() & eval() in our free Pandas course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Learn to write readable multi-condition filters, reference Python variables with @, compute new columns with eval(), and know when string expressions beat boolean masks.
What You'll Learn in This Lesson
1 Readable Filters — df.query("...")
df.query() takes a string and keeps the rows where it is true. Inside the string you write column names bare — no df["..."] — and you may use the friendly words and , or , and not instead of the bitwise & , | , ~ . A filter that needs three sets of brackets as a mask becomes one clean sentence.
2 Using Variables — the @ Reference
Filters are rarely hard-coded — the threshold often lives in a variable. Inside a query string, prefix a Python variable with @ to use its value. df.query("age > @cutoff") reads cutoff from your code. Without the @ , query assumes you mean a column called cutoff and raises an error when it cannot find one.
3 Computing Columns — df.eval()
Where query() selects rows, eval() calculates values. Hand it an arithmetic expression over your columns and it returns the result; use the "new = ..." form to attach it as a column. It keeps long formulas readable and, on big frames, can run faster by avoiding temporary intermediate arrays.
! Common Errors (And How to Fix Them)
An unquoted string value is read as a variable name:
🎯 Mini Challenge: Filter and Compute Orders
Use query and eval together on an orders table.
- Add a total column with eval
- Keep orders where total exceeds a @threshold
- Limit it to chosen regions with in @regions
❓ Frequently Asked Questions
Lesson complete — your filters read like English!
You can filter with df.query() , combine clauses with and / or , inject variables with @ , and compute new columns with df.eval() .
🚀 Up next: Replacing Values — swap, blank out, and clamp values with replace, where, and mask.
Practice quiz
What does df.query() return?
- The rows where the expression is true
- A single boolean value
- The column names only
- A sorted copy of the frame
Answer: The rows where the expression is true. query() keeps the rows for which the string expression evaluates to True.
Inside a query string, how do you reference a Python variable named cutoff?
- #cutoff
- @cutoff
- $cutoff
- %cutoff
Answer: @cutoff. Prefix the variable with @, e.g. df.query('age > @cutoff').
Which method computes a new column from an expression?
- df.filter()
- df.select()
- df.eval()
- df.where()
Answer: df.eval(). df.eval('total = price * qty') evaluates the expression and can attach it as a column.
How must a string value be written inside a double-quoted query?
- Left unquoted, like NYC
- With backticks, like
Wrap text values in single quotes so they are not read as variable names: city == 'NYC'.
Which words can replace &, |, ~ inside a query expression?
- and, or, not
- AND, OR, NOT only
- plus, minus, no
- with, without, none
Answer: and, or, not. query() accepts the readable keywords and, or, and not.
What does df.query('city in @cities') do?
- Adds a cities column
- Keeps rows whose city is in the list cities
- Sorts by city
- Renames the city column
Answer: Keeps rows whose city is in the list cities. in with @list is the readable equivalent of .isin() on a boolean mask.
By default, df.eval('total = price * qty') returns what?
- Nothing, it mutates in place silently
- A plain Python list
- A new DataFrame with the extra column
- Only the total Series
Answer: A new DataFrame with the extra column. It returns a new DataFrame with the computed column, so assign it back.
What error appears for df.query('city == NYC')?
- SyntaxError: invalid token
- ValueError: bad expression
- KeyError: NYC
- name 'NYC' is not defined
Answer: name 'NYC' is not defined. Unquoted NYC is treated as a variable name; quote it as 'NYC'.
Why might query()/eval() run faster on large frames?
- They can use the numexpr engine and avoid temporary arrays
- They skip type checking entirely
- They cache every result to disk
- They run on the GPU automatically
Answer: They can use the numexpr engine and avoid temporary arrays. pandas can evaluate the expression with numexpr, avoiding intermediate arrays.
Given df with age column, what does df.query('age > 30')['name'] return?
- The whole DataFrame
- The name values for rows where age exceeds 30
- A count of matching rows
- The age column instead
Answer: The name values for rows where age exceeds 30. query() filters rows first, then ['name'] selects that column from the result.
Continue this course
- Previous: Counting & Uniques
- Next: Replacing Values