pandas: типы столбцов и очистка по правилу

Дубли: duplicated и drop_duplicates по ключевым столбцам

Содержание курса

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

duplicated: обнаружение дублирующихся строк по subset

Метод df.duplicated() возвращает булев Series той же длины, что и исходный DataFrame. Каждое значение отвечает на вопрос: «эта строка уже встречалась выше?» Если встречалась — True, если нет — False.

По умолчанию duplicated() сравнивает сразу все столбцы. Но на практике чаще нужно проверять дублирование только по ключевым полям — например, по паре (user_id, action). Для этого есть параметр subset:

import pandas as pd

df = pd.DataFrame({
    'user_id': [1, 2, 1, 3, 2],
    'action':  ['login', 'buy', 'login', 'view', 'buy'],
    'amount':  [0, 100, 0, 50, 200]
})

mask = df.duplicated(subset=['user_id', 'action'])
print(mask)
# 0    False
# 1    False
# 2     True
# 3    False
# 4     True
# dtype: bool

print(mask.sum())  # 2 — сколько строк являются кандидатами в дубли

Строки с индексами 2 и 4 отмечены True: пара (1, 'login') уже встречалась в строке 0, а пара (2, 'buy') — в строке 1. Столбец amount в сравнение не входит — только то, что указано в subset.

Важно понимать, что duplicated(subset=...) фиксирует совпадение значений по выбранным столбцам — и ничего больше. Это не означает, что строки бизнес-эквивалентны. Посмотри на пару (2, 'buy'): строки 1 и 4 совпадают по user_id и action, но amount у них разный — 100 и 200. Это могут быть два разных события одного пользователя, а не случайный дубль. Поэтому результат duplicated() — это список кандидатов в дубли по выбранному ключу, которых нужно осмыслить, прежде чем удалять.

Булев Series из duplicated() — это обычная маска. Её можно передать в df[mask], чтобы посмотреть на строки-кандидаты:

print(df[mask])
#    user_id action  amount
# 2        1  login       0
# 4        2    buy     200

Прежде чем переходить к удалению, стоит взглянуть и на «оригиналы» рядом — например, через keep=False (это разберём в следующем разделе). Убедившись, что совпадение ключа действительно означает нежелательный повтор, а не два легитимных события, можно переходить к drop_duplicates().