0Pricing
Pandas & NumPy Academy · Урок

Метод query()

Записывайте понятные выражения фильтрации в виде строк с помощью query(), используйте переменные Python внутри запросов через @ и объединяйте фильтры в цепочку

«Метод query()» — бесплатный урок Pandas & NumPy Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения 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() — обращаться к переменным 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     3979576

Цепочки вызовов query()

Поскольку query() возвращает новый DataFrame, Вы можете объединять в цепочку несколько вызовов query() или сочетать их с другими методами Pandas в конвейере. Цепочка размещает каждый шаг фильтрации в отдельной строке, благодаря чему логику легко читать, отлаживать и изменять.

Вы также можете объединять в цепочку query() с такими методами, как .groupby(), .sort_values() или .head(), чтобы создавать компактные конвейеры анализа.

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

Сравнение query() и логической индексации

Оба метода дают одинаковый результат, но каждый подходит для своих задач. query() особенно удобен для фильтров с несколькими условиями, которые при логической индексации потребовали бы множества скобок. Логическая индексация лучше, когда условие содержит сложные выражения Python, например вызовы методов, не поддерживаемые в строках запросов.

В большинстве случаев производительность схожа; query() может быть немного быстрее для очень больших DataFrames, поскольку использует библиотеку numexpr внутри.

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

Сравнение строк в query()

Фильтровать значения строкового столбца внутри строки запроса можно, заключив строковый литерал в кавычки. Используйте двойные кавычки для внешней строки запроса и одинарные — для строкового значения или наоборот — главное, будьте последовательны. Обратите внимание: query() не поддерживает методы .str, такие как contains(); для них используйте булеву индексацию с .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

Использование операторов in и not in

Внутри строк запросов Pandas поддерживает операторы in и not in для проверки принадлежности, аналогично спискам Python. Это удобная альтернатива объединению нескольких условий == с помощью 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()

Цепочки сравнений Python, такие как 10 < price < 500, работают внутри строк запросов, благодаря чему фильтры диапазона становятся очень выразительными. При стандартной булевой индексации это невозможно без использования between() или двух отдельных условий, объединённых с помощью &.

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

Ограничения query()

query() — мощный инструмент, но у него есть несколько ограничений. Имена столбцов, содержащие пробелы или специальные символы, необходимо заключать в обратные кавычки. Очень сложные выражения Python (пользовательские функции, многострочная логика) нельзя использовать внутри строки. Кроме того, query() может давать неожиданные результаты, если имена столбцов совпадают с ключевыми словами Python, например class или if — такие имена тоже заключайте в обратные кавычки.

Если выразить условие с помощью 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

<p>Рассмотрим практический пример, в котором query() используется вместе со ссылкой на переменную и последующей цепочкой вызова groupby. Такой подход — сначала отфильтровать, затем агрегировать — позволяет не обрабатывать ненужные строки, что делает код понятнее и ускоряет работу с большими наборами данных.</p>

Вот практическая демонстрация, в которой 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: int64

Лучшие практики использования query() и цепочек методов

Использование query() внутри цепочки методов считается хорошей практикой в современном коде Pandas. Каждый шаг конвейера преобразований становится понятным и самодокументируемым. Заключайте всю цепочку в круглые скобки, чтобы переносить её на несколько строк без обратных косых черт.

Сочетайте query() с assign() для добавления столбцов, groupby() для агрегирования и pipe() для пользовательских функций, чтобы строить полностью понятные конвейеры.

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/7) и разблокировать остальной курс Pandas & NumPy Academy, подпишись на CoddyKit PRO. Курс Pandas & NumPy Academy содержит 4 уроков всего.

Чему я научусь в уроке «Метод query()»?

Записывайте понятные выражения фильтрации в виде строк с помощью query(), используйте переменные Python внутри запросов через @ и объединяйте фильтры в цепочку Ты практикуешь Pandas & NumPy Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Pandas & NumPy Academy?

Предыдущий опыт не требуется. Pandas & NumPy Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Метод query()»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Pandas & NumPy Academy?

Да. Каждый урок Pandas & NumPy Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Булева индексация DataFrames
  2. Метод query()
  3. Фильтры isin() и between()
  4. Выбор столбцов по шаблону
← Назад к Pandas & NumPy Academy