5 эффективных техник удаления строк по условию в Pandas

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

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

  • Аналитики данных
  • Студенты и начинающие специалисты в области анализа данных
  • Профессионалы, желающие улучшить свои навыки работы с Pandas и фильтрацией данных

    Работа с данными часто напоминает кулинарию — прежде чем приготовить изысканное блюдо, нужно избавиться от всего лишнего. В мире анализа данных "лишнее" — это строки, не соответствующие вашим критериям. Фильтрация DataFrame в Pandas — одна из самых распространенных операций, с которой сталкивается каждый аналитик данных. Но выполнить её можно разными способами, и выбор правильного метода может значительно повлиять на производительность и читаемость кода. Давайте разберем пять мощных техник, которые превратят вас из начинающего кулинара данных в шеф-повара аналитики. 🔍

Освоить удаление строк по условию в Pandas — лишь вершина айсберга навыков аналитика данных. На курсе Профессия аналитик данных от Skypro вы не только освоите все тонкости манипуляций с данными, но и научитесь строить предиктивные модели, визуализировать результаты и принимать решения на основе данных. Практические кейсы и поддержка менторов помогут превратить теорию в реальные рабочие навыки, востребованные на рынке.

Зачем и когда нужно удалять строки в pandas

Чистые данные — основа качественного анализа. Удаление строк в Pandas становится необходимостью во множестве сценариев:

  • Очистка от пропущенных значений (NaN, None)
  • Удаление выбросов и аномалий
  • Фильтрация устаревших или нерелевантных записей
  • Создание подмножества данных для специфического анализа
  • Повышение производительности при работе с большими датасетами

Правильная предобработка данных может существенно повлиять на результаты анализа. Согласно исследованиям, аналитики тратят до 80% рабочего времени именно на подготовку данных, и фильтрация — важнейший этап этого процесса.

Александр Петров, Lead Data Scientist

Однажды наша команда столкнулась с проблемой при анализе данных о потреблении электроэнергии. Модель давала абсурдные прогнозы, и мы долго не могли понять причину. Оказалось, в датасете присутствовали строки с отрицательными значениями потребления — результат ошибок измерения.

Я написал простой код для фильтрации:

df = df[df['consumption'] > 0]

Эта одна строка кода спасла проект. После удаления некорректных строк точность прогнозирования выросла с 65% до 91%. Этот случай наглядно показал, насколько критичной может быть правильная фильтрация данных. С тех пор детальная проверка и очистка данных — первый шаг в каждом нашем проекте.

Прежде чем перейти к конкретным методам, важно понимать общую логику: при фильтрации мы создаём новый DataFrame, содержащий только те строки, которые соответствуют определенным условиям. Это можно сделать как путем выбора нужных строк, так и путем удаления ненужных.

Теперь рассмотрим пять эффективных способов удаления строк по условию, начиная с самого фундаментального метода — булевой индексации.

Пошаговый план для смены профессии

Булевая индексация для фильтрации DataFrame

Булевая индексация — наиболее интуитивный и широко используемый метод фильтрации данных в Pandas. Суть подхода проста: мы создаем серию булевых значений (True/False) для каждой строки и используем её для отбора только тех строк, которые отвечают нашему условию.

Базовый синтаксис выглядит так:

# Оставить строки, где значение столбца 'age' больше 30
filtered_df = df[df['age'] > 30]

# Удалить эти же строки (инвертировав условие)
filtered_df = df[~(df['age'] > 30)]

Булевая индексация поддерживает составные условия с использованием логических операторов:

# Логическое И (AND) – оба условия должны выполняться
filtered_df = df[(df['age'] > 30) & (df['salary'] > 50000)]

# Логическое ИЛИ (OR) – хотя бы одно условие должно выполняться
filtered_df = df[(df['department'] == 'Sales') | (df['experience'] > 5)]

Преимущества булевой индексации:

  • Интуитивно понятный синтаксис 🧠
  • Высокая производительность благодаря векторизации операций
  • Поддержка сложных составных условий
  • Прямая работа с датафреймом без промежуточных шагов

Для сложных условий иногда полезно создавать маску заранее:

# Создание булевой маски
mask = (df['age'] > 30) & (df['salary'] > 50000) | ((df['department'] == 'IT') & (df['experience'] > 3))

# Применение маски
filtered_df = df[mask]

Булевая индексация особенно полезна при работе с числовыми данными и простыми строковыми сравнениями. Для текстовых данных можно использовать методы строк:

# Фильтрация по части строки
filtered_df = df[df['email'].str.contains('@gmail.com')]

# Фильтрация по регулярному выражению
filtered_df = df[df['phone_number'].str.match(r'^\+7')]

Операция Синтаксис Описание Производительность
Простое условие df[df['col'] > value] Фильтрация по одному условию Высокая
Множественные условия (AND) df[(cond1) & (cond2)] Все условия должны выполняться Средняя
Множественные условия (OR) df[(cond1) | (cond2)] Хотя бы одно условие должно выполняться Средняя
Отрицание условия df[~(condition)] Инвертирование условия Высокая
Проверка на вхождение в список df[df['col'].isin(values)] Значение должно присутствовать в списке Высокая

Для более сложных сценариев или для явного удаления строк (а не отбора нужных) существуют другие методы, которые мы рассмотрим далее.

Метод drop() для удаления строк по условию

В отличие от булевой индексации, которая отбирает нужные строки, метод drop() явно удаляет ненужные. Этот подход особенно удобен, когда вы точно знаете, какие строки хотите исключить из анализа.

Основной синтаксис метода drop():

# Удаление строк по метке индекса
df_cleaned = df.drop(labels=[0, 10, 25], axis=0)

# Удаление строк по условию
df_cleaned = df.drop(df[df['age'] < 18].index)

Обратите внимание на параметр axis=0 — он указывает, что мы удаляем строки (а не столбцы). Также важен параметр inplace, который определяет, будет ли изменен исходный DataFrame или возвращен новый:

# Создание нового DataFrame без указанных строк
new_df = df.drop(labels=[0, 1, 2], axis=0, inplace=False)

# Изменение исходного DataFrame
df.drop(labels=[0, 1, 2], axis=0, inplace=True)

Метод drop() особенно полезен в следующих случаях:

  • Удаление конкретных строк по их индексам
  • Удаление строк, не соответствующих бизнес-логике
  • Очистка датасета от выбросов
  • Последовательная фильтрация данных в несколько этапов

Для удаления строк по условию с помощью drop(), необходимо сначала получить индексы строк, удовлетворяющих условию:

# Удалить строки, где значение в столбце 'score' меньше 50
indices_to_drop = df[df['score'] < 50].index
df_cleaned = df.drop(indices_to_drop, axis=0)

Для сложных условий:

# Удалить строки с пропущенными значениями в столбцах 'name' или 'email'
missing_values_mask = df['name'].isna() | df['email'].isna()
indices_with_missing = df[missing_values_mask].index
df_cleaned = df.drop(indices_with_missing, axis=0)

Мария Соколова, Data Analyst

Мне поручили проанализировать данные о продажах крупного интернет-магазина. В датасете было более миллиона строк, и я заметила странную закономерность: некоторые транзакции имели нереально высокие значения — более 10 млн рублей за одну покупку.

Изначально я пыталась использовать булевую индексацию:

filtered_df = df[df['transaction_amount'] <= 1000000]

Но это был лишь первый шаг очистки. Нужно было также удалить транзакции с подозрительно короткими временными интервалами и от несуществующих пользователей. Я решила применить метод drop() последовательно:

# Шаг 1: Удаление аномально высоких транзакций
indices_high_transactions = df[df['transaction_amount'] > 1000000].index
df = df.drop(indices_high_transactions, axis=0)

# Шаг 2: Удаление подозрительно частых транзакций
df['time_diff'] = df.groupby('user_id')['timestamp'].diff()
indices_suspicious_timing = df[df['time_diff'] < '00:00:10'].index
df = df.drop(indices_suspicious_timing, axis=0)

# Шаг 3: Удаление транзакций от несуществующих пользователей
indices_fake_users = df[~df['user_id'].isin(valid_users_list)].index
df = df.drop(indices_fake_users, axis=0)

Такой пошаговый подход с использованием drop() позволил мне четко документировать процесс очистки и проследить, сколько строк было удалено на каждом этапе. В результате удалось выявить мошеннические транзакции на сумму около 15 млн рублей, что составляло почти 5% общего оборота. Клиент был впечатлен этими находками и внедрил автоматическую систему фильтрации на основе моего кода.

Несмотря на удобство, у метода drop() есть свои ограничения — для удаления строк по сложным условиям он требует дополнительного шага создания индексов. Поэтому для некоторых задач лучше подойдут другие методы.

Использование loc[] и iloc[] при фильтрации данных

Методы loc[] и iloc[] представляют мощные инструменты для точного индексирования и выбора данных в Pandas. Они предлагают более гибкий подход к фильтрации, позволяя одновременно выбирать строки по условию и нужные столбцы.

Ключевое различие между ними:

  • loc[] работает с метками индексов и именами столбцов
  • iloc[] работает с числовыми позициями (0-based индексацией)

Использование loc[] для фильтрации строк по условию:

# Выбрать строки, где возраст больше 30, и только столбцы 'name', 'age', 'salary'
result = df.loc[df['age'] > 30, ['name', 'age', 'salary']]

# Выбрать строки в диапазоне индексов с условием
result = df.loc[(df.index >= 10) & (df.index < 50) & (df['status'] == 'active'), :]

С помощью iloc[] мы можем фильтровать по числовым позициям:

# Выбрать первые 10 строк, соответствующие условию
mask = df['age'] > 30
result = df.iloc[mask.values][:10, :]

# Выбрать каждую вторую строку из отфильтрованных данных
result = df.iloc[mask.values][::2, [0, 1, 3]]

Методы loc[] и iloc[] особенно полезны, когда требуется:

  • Одновременно фильтровать строки и выбирать определенные столбцы
  • Работать с именованными индексами (loc[])
  • Выбирать данные по позиции (iloc[])
  • Сочетать фильтрацию с операциями слайсинга

Пример сложной фильтрации с использованием loc[]:

# Отфильтровать сотрудников IT-отдела с опытом > 5 лет и зарплатой > 100000
condition = (df['department'] == 'IT') & (df['experience'] > 5) & (df['salary'] > 100000)
senior_it_staff = df.loc[condition, ['name', 'position', 'salary', 'hire_date']]

Комбинация условий с выбором диапазонов строк:

# Выбрать записи за определенный период с определенным статусом
date_mask = (df['date'] >= '2023-01-01') & (df['date'] <= '2023-03-31')
result = df.loc[date_mask & (df['status'] == 'completed'), :]

Метод Работа с Типичное применение Синтаксис для фильтрации
loc[] Метки индексов, имена столбцов Когда важны имена/метки данных df.loc[df['col'] > value, ['col1', 'col2']]
iloc[] Позиционные индексы (0-based) Когда важны позиции в датафрейме df.iloc[mask.values, [0, 1, 2]]
Boolean indexing Булевая маска для всех строк Простая фильтрация по условию df[df['col'] > value]
loc[] + слайсинг Диапазоны по меткам Выбор диапазона по условию df.loc[mask, 'col1':'col5']
iloc[] + слайсинг Числовые диапазоны Выбор числовых диапазонов строк/столбцов df.iloc[mask.values, 0:5:2]

Особое преимущество loc[] и iloc[] заключается в возможности одновременной фильтрации строк и столбцов, что делает код более компактным и читаемым. Однако для еще более сложных сценариев фильтрации существуют специализированные методы, такие как query() и apply(), которые мы рассмотрим далее.

Метод query() и apply() для сложного отбора строк

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

Метод query() позволяет использовать выражения в стиле SQL для фильтрации DataFrame:

# Простой запрос
filtered_df = df.query('age > 30 and salary > 50000')

# Сложный запрос с несколькими условиями
filtered_df = df.query('(department == "Sales" or department == "Marketing") and experience > 3 and performance_score >= 4')

Преимущества метода query():

  • Читаемый синтаксис, похожий на SQL
  • Возможность использовать переменные из окружения с префиксом @
  • Оптимизированная производительность для сложных условий
  • Снижение вероятности ошибок в сложных логических выражениях

Пример использования внешних переменных в query():

min_age = 25
max_salary = 100000
departments = ['IT', 'Finance', 'HR']

filtered_df = df.query('age >= @min_age and salary <= @max_salary and department in @departments')

Метод apply(), с другой стороны, позволяет применять произвольные функции к каждой строке или столбцу DataFrame, что делает его невероятно гибким для сложных условий:

# Определение функции фильтрации
def filter_condition(row):
if row['age'] < 30:
return row['experience'] >= 2
elif 30 <= row['age'] < 40:
return row['experience'] >= 5
else:
return row['experience'] >= 8

# Применение функции к каждой строке
filtered_df = df[df.apply(filter_condition, axis=1)]

Метод apply() особенно полезен, когда:

  • Условия фильтрации слишком сложны для выражения через стандартные операторы
  • Необходима дополнительная логика или вычисления в процессе фильтрации
  • Требуется доступ к нескольким значениям строки одновременно
  • Нужно применить пользовательские алгоритмы обработки

Продвинутый пример с использованием apply():

# Функция для выявления аномалий на основе множества факторов
def is_anomaly(row):
# Правило 1: Высокая транзакция в нерабочее время
if row['amount'] > 10000 and (row['hour'] < 9 or row['hour'] > 18):
return True

# Правило 2: Необычное местоположение для пользователя
if row['location'] not in row['usual_locations'] and row['amount'] > 5000:
return True

# Правило 3: Слишком много транзакций за короткий период
if row['transactions_last_hour'] > 5:
return True

return False

# Отфильтровать аномальные транзакции
normal_transactions = df[~df.apply(is_anomaly, axis=1)]

Сравнение методов query() и apply():

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

Для максимальной производительности при использовании apply() можно применять векторизацию там, где это возможно:

# Медленный подход с apply
df_slow = df[df.apply(lambda row: row['a'] * row['b'] > 100, axis=1)]

# Быстрый векторизованный подход
df_fast = df[df['a'] * df['b'] > 100]

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

Мы рассмотрели пять эффективных способов удаления строк по условию в Pandas. Каждый метод имеет свои сильные стороны: булевая индексация интуитивно понятна и универсальна, метод drop() позволяет явно удалять ненужные строки, loc[] и iloc[] обеспечивают точный контроль над выбором данных, а query() и apply() справляются со сложными сценариями фильтрации. Выбор оптимального метода зависит от конкретной задачи, объема данных и требований к читаемости кода. Помните: хороший аналитик данных не просто знает множество методов, но умеет выбирать наиболее подходящий инструмент для каждой ситуации. Это не только экономит вычислительные ресурсы, но и делает код более понятным и поддерживаемым.

Загрузка...