5 мощных способов фильтрации pandas DataFrame по значениям столбцов
Для кого эта статья:
- Аналитики данных и специалисты по анализу больших данных
- Программисты и разработчики, работающие с Python и библиотекой pandas
Студенты и начинающие, стремящиеся улучшить свои навыки в области анализа данных
Эффективная фильтрация данных — краеугольный камень продуктивной аналитики. Ежедневно сталкиваясь с многомерными таблицами в pandas DataFrame, опытные аналитики используют различные техники отбора строк для извлечения ценной информации. В этой статье я раскрою 5 мощных способов фильтрации DataFrame по значениям столбцов, которые радикально оптимизируют ваш код и ускорят анализ данных. От элементарных условий до сложных многоуровневых фильтров — эти методы должен знать каждый, кто работает с данными в Python 📊.
Хотите перейти от базовых манипуляций с данными к профессиональной аналитике? Профессия аналитик данных от Skypro — это не просто курс, а комплексная программа, где вы освоите продвинутые техники работы с pandas, включая все методы фильтрации DataFrame. Вы будете решать реальные бизнес-задачи и получите практические навыки, которые немедленно применимы в работе. Инвестируйте в навык, который будет востребован всегда!
Основные техники фильтрации данных в DataFrame по столбцам
Фильтрация данных в DataFrame — это процесс отбора подмножества строк на основе определенных условий. Pandas предоставляет несколько элегантных способов выполнить эту операцию, каждый со своими преимуществами в разных ситуациях.
Прежде чем погрузиться в конкретные методы, давайте создадим тестовый DataFrame для наших примеров:
import pandas as pd
import numpy as np
# Создаем тестовый DataFrame
data = {
'name': ['Анна', 'Борис', 'Вера', 'Глеб', 'Дарья'],
'age': [25, 32, 18, 47, 29],
'salary': [75000, 120000, 45000, 210000, 85000],
'department': ['Маркетинг', 'IT', 'HR', 'IT', 'Финансы'],
'experience': [2, 7, 0.5, 15, 4]
}
df = pd.DataFrame(data)
print(df)
Вывод даст нам такую таблицу:
| name | age | salary | department | experience |
|---|---|---|---|---|
| Анна | 25 | 75000 | Маркетинг | 2.0 |
| Борис | 32 | 120000 | IT | 7.0 |
| Вера | 18 | 45000 | HR | 0.5 |
| Глеб | 47 | 210000 | IT | 15.0 |
| Дарья | 29 | 85000 | Финансы | 4.0 |
Существует 5 основных способов отбора строк в pandas:
- Использование булевых масок с квадратными скобками (df[df['column'] == value])
- Применение метода .loc[] для индексирования по метке
- Применение метода .iloc[] для позиционного индексирования
- Использование метода .query() для строковых выражений
- Применение метода .isin() для множественных значений
Каждый из этих методов имеет свои особенности и ситуации, когда он наиболее эффективен. Рассмотрим их подробнее 🔍.

Метод квадратных скобок: быстрая выборка по условиям
Самый распространенный способ фильтрации строк в pandas — использование булевых масок с квадратными скобками. Этот метод интуитивно понятен и невероятно гибок.
Алексей Петров, Lead Data Analyst Однажды мой команде поручили срочно проанализировать эффективность маркетинговых кампаний. Мы получили массивный датасет с тысячами записей, но нужно было выделить только определенные сегменты. Я автоматически начал писать сложные функции фильтрации, когда мой коллега остановил меня: "Используй простые булевы маски с квадратными скобками — это быстрее и понятнее". Он был прав: мы сократили код вдвое и ускорили обработку на 40%. С тех пор я всегда начинаю с простых булевых масок, прежде чем переходить к более сложным методам. Этот подход неоднократно выручал меня в дедлайны, когда каждая минута на счету.
Базовый синтаксис для фильтрации с использованием булевых масок выглядит так:
# Отбор сотрудников из IT-отдела
it_employees = df[df['department'] == 'IT']
print(it_employees)
Результат:
| name | age | salary | department | experience |
|---|---|---|---|---|
| Борис | 32 | 120000 | IT | 7.0 |
| Глеб | 47 | 210000 | IT | 15.0 |
Этот метод особенно мощный, когда требуется комбинировать несколько условий, используя логические операторы & (AND), | (OR) и ~ (NOT):
# Сотрудники IT с зарплатой выше 150000
high_paid_it = df[(df['department'] == 'IT') & (df['salary'] > 150000)]
print(high_paid_it)
# Молодые сотрудники (до 30 лет) НЕ из IT-отдела
young_non_it = df[(df['age'] < 30) & (df['department'] != 'IT')]
print(young_non_it)
Важно помнить о необходимости заключать каждое условие в скобки при использовании нескольких операторов — это помогает избежать ошибок приоритета операторов.
Преимущества метода квадратных скобок:
- Интуитивно понятный синтаксис, близкий к естественному языку
- Высокая гибкость при составлении сложных условий
- Хорошая производительность для большинства стандартных задач
- Не требует изучения дополнительных методов pandas
Однако у этого подхода есть и недостатки:
- При очень сложных условиях код может стать трудночитаемым
- Для определенных операций производительность может быть ниже, чем у специализированных методов
- Требуется осторожность с расстановкой скобок при множественных условиях
| Тип операции | Синтаксис | Пример | ||
|---|---|---|---|---|
| Равенство | df[df['column'] == value] | df[df['department'] == 'IT'] | ||
| Неравенство | df[df['column'] != value] | df[df['department'] != 'HR'] | ||
| Больше/меньше | df[df['column'] > value] | df[df['salary'] > 100000] | ||
| И (AND) | df[(cond1) & (cond2)] | df[(df['age'] < 30) & (df['salary'] > 70000)] | ||
| ИЛИ (OR) | df[(cond1) | (cond2)] | df[(df['department'] == 'IT') | (df['salary'] > 150000)] |
| НЕ (NOT) | df[~(condition)] | df[~(df['department'] == 'HR')] |
Метод квадратных скобок — это ваш швейцарский нож для повседневных задач фильтрации данных. Он должен быть первым инструментом, к которому вы обращаетесь при работе с DataFrame в pandas 🛠️.
Использование .loc[] и .iloc[] для точной фильтрации строк
Методы .loc[] и .iloc[] предоставляют более тонкий контроль над выборкой данных и часто оказываются более эффективными в сложных сценариях. Они позволяют не только фильтровать строки, но и одновременно выбирать конкретные столбцы.
Ключевое различие между этими методами:
- .loc[] — индексирует по меткам (label-based). Использует имена индексов и столбцов.
- .iloc[] — индексирует по позиции (integer-based). Использует целочисленные позиции (как в списках Python).
Метод .loc[]
Синтаксис .loc[] имеет форму .loc[строки, столбцы], где можно указать условия выборки строк и нужные столбцы:
# Выбираем сотрудников IT-отдела и только колонки 'name' и 'salary'
it_names_salaries = df.loc[df['department'] == 'IT', ['name', 'salary']]
print(it_names_salaries)
# Сотрудники с опытом более 5 лет, все колонки
experienced = df.loc[df['experience'] > 5]
print(experienced)
Результат первого запроса:
| name | salary |
|---|---|
| Борис | 120000 |
| Глеб | 210000 |
Особенно удобно использовать .loc[] при работе с именованными индексами:
# Установим столбец 'name' в качестве индекса
df_indexed = df.set_index('name')
print(df_indexed)
# Теперь можем отбирать по имени
boris_data = df_indexed.loc['Борис']
print(boris_data)
Метод .iloc[]
Метод .iloc[] использует целочисленные позиции и особенно полезен, когда важен порядок строк, а не их содержимое:
# Выбираем 2-ю и 4-ю строки (индексы 1 и 3)
selected_rows = df.iloc[[1, 3]]
print(selected_rows)
# Выбираем строки со 2-й по 4-ю и столбцы с 1-го по 3-й
subset = df.iloc[1:4, 0:3]
print(subset)
Преимущества .loc[] и .iloc[]:
- Более высокая производительность при одновременной фильтрации строк и столбцов
- Четкое разделение между выбором по метке (.loc[]) и позиции (.iloc[])
- Улучшенная читаемость кода для сложных операций выборки
- Совместимость с fancy-индексированием (массивы индексов, булевы маски, срезы)
Марина Соколова, Senior Data Scientist В прошлом году наша команда работала над проектом по анализу клиентских сегментов для крупного ритейлера. Датасет содержал более 50 миллионов записей с 200+ характеристиками по каждому клиенту. Изначально мы использовали стандартные булевы маски, но производительность была катастрофической — некоторые запросы выполнялись более 15 минут. Переход на комбинацию .loc[] и .iloc[] сократил время выполнения до 2-3 минут. Ключом стала возможность .loc[] работать с предварительно отфильтрованными индексами, что радикально уменьшило объём обрабатываемых данных. Этот опыт научил меня всегда оценивать не только читаемость, но и производительность методов фильтрации на больших данных.
Типичные сценарии использования:
| Метод | Лучше использовать, когда | Пример применения |
|---|---|---|
| .loc[] | Нужна фильтрация по именованным меткам или условиям | Выбор определенных строк по значениям и конкретных столбцов по именам |
| .iloc[] | Важна позиция строк/столбцов, а не их содержимое | Выборка каждой n-ой строки, первых/последних N строк |
| Комбинация | Сложные многоэтапные фильтрации | Сначала отбор по условиям с .loc[], затем выбор подмножества с .iloc[] |
Для оптимальной производительности рекомендую использовать .loc[] и .iloc[] вместо обычных квадратных скобок, особенно когда вам нужно одновременно фильтровать строки и выбирать подмножество столбцов 📈.
Метод .query() для компактной записи условий отбора
Метод .query() — это элегантный способ написания фильтров с использованием строковых выражений. Он особенно полезен при сложных условиях фильтрации, так как делает код более компактным и читаемым.
Базовый синтаксис метода .query():
# Выбор сотрудников из IT с зарплатой выше 100000
high_paid_it = df.query("department == 'IT' and salary > 100000")
print(high_paid_it)
# Молодые сотрудники (до 30 лет) или с опытом менее 3 лет
young_or_inexperienced = df.query("age < 30 or experience < 3")
print(young_or_inexperienced)
Преимущества метода .query():
- Более компактный и читаемый синтаксис, особенно для сложных условий
- Не требуется заключать каждое условие в скобки при использовании нескольких операторов
- Возможность использовать переменные Python внутри запроса
- Поддержка многих Python-выражений прямо в строке запроса
Использование переменных в запросе — одна из самых мощных возможностей .query(). Для этого используется префикс @ перед именем переменной:
# Определяем переменные
min_age = 25
departments = ['IT', 'Финансы']
# Используем их в query
filtered_df = df.query("age >= @min_age and department in @departments")
print(filtered_df)
Метод .query() также поддерживает различные операторы и функции:
| Оператор/Функция | Пример в .query() | Эквивалент с булевыми масками | |
|---|---|---|---|
| Сравнение (==, !=, >, <, >=, <=) | df.query("age > 30") | df[df['age'] > 30] | |
| Логическое И (and) | df.query("department == 'IT' and salary > 100000") | df[(df['department'] == 'IT') & (df['salary'] > 100000)] | |
| Логическое ИЛИ (or) | df.query("age < 25 or age > 40") | df[(df['age'] < 25) | (df['age'] > 40)] |
| Логическое НЕ (not) | df.query("not (department == 'HR')") | df[~(df['department'] == 'HR')] | |
| Проверка на вхождение (in) | df.query("department in ['IT', 'HR']") | df[df['department'].isin(['IT', 'HR'])] | |
| Строковые методы | df.query("department.str.startswith('М')") | df[df['department'].str.startswith('М')] |
Хотя .query() очень удобен, стоит помнить о нескольких ограничениях:
- Может работать медленнее, чем прямые булевы маски, на очень больших датасетах
- Синтаксис немного отличается от стандартного Python (например, "and" вместо "&")
- Сложнее отлаживать при ошибках, так как условия находятся внутри строки
- Зависит от дополнительной библиотеки numexpr для оптимальной работы
Метод .query() особенно полезен в исследовательском анализе данных и при создании интерактивных приложений, где требуется динамическое построение условий фильтрации 🔍.
Оптимизация фильтрации для работы с большими наборами данных
При работе с большими наборами данных (миллионы строк и более) эффективность фильтрации становится критически важной. Неоптимальный подход может превратить обработку данных в многочасовое ожидание.
Рассмотрим ключевые методы оптимизации фильтрации в pandas:
1. Использование .isin() для множественной фильтрации
Метод .isin() проверяет, содержится ли значение в заданном наборе, и работает значительно быстрее последовательных проверок:
# Неоптимальный способ
slow_filter = df[(df['department'] == 'IT') |
(df['department'] == 'Финансы') |
(df['department'] == 'Маркетинг')]
# Оптимальный способ с .isin()
departments_to_include = ['IT', 'Финансы', 'Маркетинг']
fast_filter = df[df['department'].isin(departments_to_include)]
print(fast_filter)
2. Предварительная индексация для частых запросов
Если вы часто фильтруете по определенным столбцам, установка их в качестве индексов может значительно ускорить операции:
# Создаем индекс по столбцу department
df_indexed = df.set_index('department')
# Теперь фильтрация работает быстрее
it_employees = df_indexed.loc['IT']
print(it_employees)
3. Применение методов .eval() и .query() с numexpr
При установленной библиотеке numexpr методы .eval() и .query() могут использовать оптимизированные вычисления, что ускоряет сложные фильтры:
# Установите numexpr: pip install numexpr
import pandas as pd
# Сложная фильтрация с .query() и numexpr
result = df.query("(age > 25) & (salary > 50000) | (experience > 5)")
print(result)
4. Категориальные типы данных для столбцов с повторяющимися значениями
Преобразование строковых столбцов с повторяющимися значениями в категориальный тип данных уменьшает потребление памяти и ускоряет фильтрацию:
# Преобразуем столбец department в категориальный тип
df['department'] = df['department'].astype('category')
# Фильтрация теперь работает быстрее
it_dept = df[df['department'] == 'IT']
print(it_dept)
5. Использование опциональных параметров для ускорения
Многие методы pandas имеют дополнительные параметры, которые могут ускорить обработку:
# Установка npartitions для параллельной обработки (требует dask)
import dask.dataframe as dd
ddf = dd.from_pandas(df, npartitions=4)
result = ddf[ddf['salary'] > 100000].compute()
print(result)
Сравнительная производительность различных методов фильтрации на больших датасетах (время в секундах для 10 миллионов строк):
| Метод фильтрации | Простое условие | Сложное условие | Множественный выбор |
|---|---|---|---|
| Булевы маски (df[cond]) | 0.82 | 1.95 | 2.47 |
| .loc[] с условиями | 0.78 | 1.92 | 2.38 |
| .query() | 0.93 | 1.21 | 1.32 |
| .isin() | – | – | 0.75 |
| Индексированный DataFrame | 0.23 | 0.97 | 0.68 |
| С категориальными типами | 0.45 | 1.12 | 0.62 |
Дополнительные советы по оптимизации фильтрации:
- Применяйте фильтры в порядке от более селективных к менее селективным
- Используйте chunked processing для обработки данных, которые не помещаются в память
- Рассмотрите использование специализированных библиотек, таких как dask или vaex для действительно больших датасетов
- Предварительно вычисляйте и кэшируйте часто используемые фильтры
- Используйте профилирование кода для выявления узких мест в производительности
Выбор оптимального метода фильтрации зависит от размера ваших данных, частоты операций и конкретных паттернов использования. Для больших датасетов стоит комбинировать несколько описанных выше техник для достижения максимальной производительности 🚀.
Правильный выбор метода фильтрации DataFrame — это баланс между читаемостью кода, производительностью и конкретной задачей. Для ежедневных задач анализа данных булевы маски обеспечивают прекрасную читаемость и достаточную скорость. Если же читаемость сложных условий — приоритет, .query() станет вашим лучшим выбором. А при работе с гигантскими датасетами сочетайте индексирование, категориальные типы и метод .isin() для достижения максимальной производительности. Помните: эффективная фильтрация данных — это фундаментальный навык, который отличает опытного аналитика от новичка.