Anti-join: пользователи, которые ни разу не купили
// Условие
Есть две таблицы: df (все зарегистрированные юзеры) и orders (заказы). Не все юзеры делали заказы — именно их нужно найти.
Верни DataFrame с колонками
user_id, signup_date, country, plan. Сортировка по signup_date asc.Идиоматичный pandas-способ — left join с indicator=True, потом фильтр по 'left_only'. Есть и короткий альтернативный вариант через isin.
// Данные
user_id, signup_date, country, planorders:
order_id, user_id, amount, order_date — доступна напрямую в namespace// Решение
Подсказка
Классический anti-join: df.merge(orders[['user_id']].drop_duplicates(), on='user_id', how='left', indicator=True). После merge у «непокупателей» в колонке _merge будет значение 'left_only'.
Отфильтруй: [merged['_merge'] == 'left_only']. Убери лишнюю колонку _merge через .drop(columns='_merge').
Альтернатива через isin — короче: df[~df['user_id'].isin(orders['user_id'])]. Оба способа дают одинаковый результат — знай оба.
Сначала попробуй сам → Показать решение
df = load_data() # users
# orders уже в namespace
# Anti-join через indicator=True
merged = df.merge(
orders[['user_id']].drop_duplicates(),
on='user_id', how='left', indicator=True
)
result = (merged[merged['_merge'] == 'left_only']
.drop(columns='_merge')
.sort_values('signup_date')
.reset_index(drop=True))
print(result)
print(f"\nНепокупателей: {len(result)} из {len(df)} юзеров")
Anti-join — pandas-аналог SQL LEFT JOIN ... WHERE right.key IS NULL. Два способа:
1) merge(indicator=True) + фильтр 'left_only' — явный, хорошо читается, удобен когда потом нужны колонки из правой таблицы;
2) df[~df['user_id'].isin(orders['user_id'])] — короче, но чуть медленнее на больших данных из-за построения множества.
На собесе спросят оба варианта и разницу в производительности. «Churned without converting» — один из главных сегментов для реактивационных кампаний: люди дошли до регистрации, но так и не купили.