5 мощных способов фильтрации pandas DataFrame по значениям столбцов

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Аналитики данных и специалисты по анализу больших данных
  • Программисты и разработчики, работающие с 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() для достижения максимальной производительности. Помните: эффективная фильтрация данных — это фундаментальный навык, который отличает опытного аналитика от новичка.

Загрузка...