Обсудить задачу
кейс · автоматизация · r&d модель обучена

Прогноз оттока в фитнес-клубе: пять портретов вместо одного списка

коротко

Собрал предиктивную модель оттока для сети фитнес-клубов на модельных данных: 20 000 клиентов, 5 клубов, 18 месяцев истории. Главное, что вынес: общий рейтинг риска по всей базе – ловушка. Он забивается одним портретом клиентов, а уходящие из «надёжных» групп в список не попадают вообще. Разделил базу на пять портретов и стал брать верхние 25% риска внутри каждого – качество ранжирования выросло, а вместе с ним появился ответ на вопрос, который клуб раньше не задавал: какое предложение делать каждому. ROC-AUC 0,97, в верхних 10% базы концентрация оттока в 8 раз выше средней. Данные модельные – методика настоящая.

ОТТОК ЗА 15 ДНЕЙ ПО ПОРТРЕТАМ, % 0 12 24 24% 18% 7% 4% 1% купил месяц живёт далеко нет телефона ходит часто годовой партнёр
рис. 01 / разрыв между портретами – 24 разамодельные данные
ОТРАСЛЬфитнес · сети клубов
ФОРМАТr&d · модельные данные
ЗАПУСКиюль 2026
СТАТУСмодель обучена

Задача

К нам приходит сеть фитнес-клубов с понятной болью: клиенты уходят, а понять, кто именно и когда – нельзя. В фитнесе это ощущается сильнее, чем в других подписках: человек не пишет заявление и не отменяет договор. Он просто перестаёт ходить. Формально абонемент ещё действует, фактически клиента уже нет.

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

Задача формулируется в два шага. Первый: найти тех, кто на грани, заранее. Второй, который обычно забывают: понять, что именно им предложить.

Почему общий список по базе не работает

Первое, что напрашивается – обучить модель, отсортировать всю базу по риску и обзванивать верхушку. Так я и сделал, и на этом обжёгся.

В верх общего рейтинга попадают почти одни клиенты с высоким базовым риском: те, кто купил месяц и сходил два раза. У них риск ухода 24% против 1% у клиента с годовым корпоративным контрактом. Общий список ими и забивается.

Проблема в том, что уходящие есть и в надёжных группах, и терять их обиднее: такой клиент платит вперёд, приносит доптраты, держится дольше. Но в общий топ он не попадёт никогда – его риск ниже, чем у любого «месячника».

И вторая, менее очевидная беда. Вероятность 40% значит разное для разных людей. Для клиента с годовым контрактом это ЧП: что-то случилось – травма, переезд, конфликт с тренером. Для купившего месяц – обычный вторник. Один порог для обоих бессмысленен.

Пять портретов вместо одного списка

Разделил базу на пять групп – по поведению и условиям, а не по демографии.

портретдоля базыотток за 15 днейчем отличается
Купил месяц и пропал30%24%короткий абонемент, ходит редко, активность просела
Живёт далеко15%18%клуб не по пути, знакомых в зале нет
Нет телефона в базе10%7%средний по всему, но с ним нельзя связаться
Ходит часто19%4%2,8 раза в неделю, абонемент тоже короткий
Годовой от партнёра26%1%оплачен работодателем, ходит на групповые

Разрыв между крайними – в 24 раза. Работать с ними одинаково – всё равно что лечить перелом и насморк одной таблеткой.

Отдельно стоит посмотреть на два средних портрета. У «ходит часто» абонемент такой же короткий, как у самого рискового – 2,6 месяца против 2,0. А отток в шесть раз ниже. Решает не длина контракта, а привычка. Это ломает интуицию владельца, который считает, что спасение в годовых картах: карта не удерживает, удерживает регулярность посещений.

Как это работает

  1. Собираем данные. Минимум – кто и когда пришёл, что покупал и когда. Если клуб ведёт журнал посещений (турникеты, отметки на ресепшене, вход по QR в приложении) – точность заметно выше. Обязательно нужны ушедшие: модель учится на разнице между теми, кто остался, и теми, кто перестал ходить. По активной базе учиться не на чем – примеров ухода в ней нет.
  2. Режем историю снапшотами. Каждые две недели фиксируем состояние клиента на этот день и считаем признаки строго по данным до этой даты. Метка – ушёл ли он в следующие 15 дней. Это единственный способ учиться честно: если хоть один признак заглянет в будущее, модель покажет красивые цифры и развалится в проде.
  3. Обучаем градиентный бустинг. CatBoost, два десятка признаков, валидация строго по времени: учимся на раннем периоде, проверяем на позднем. Случайное разбиение здесь врёт – оно позволяет подглядеть будущее соседних снапшотов того же клиента.
  4. Ранжируем внутри портрета. Модель считает риск каждому, дальше берём верхние 25% в каждом портрете отдельно. Сам портрет в обучение не подаётся – это ярлык для работы с результатом. Модель получает только сырые признаки, из которых портрет и складывается: у реального клиента метки «портрет 3» в базе нет.
  5. Отдаём боту. Список с причиной по каждому уходит голосовому боту – он обзванивает и делает предложение. Разное для разных портретов.

Что предлагать: плюшка под портрет

Главное правило – не сваливаться в скидку. Из пяти портретов она уместна для одного, и то как апсейл.

Купил месяц и пропал. У него нет привычки, деньги ни при чём. Работает бесплатное занятие с тренером или запись на групповое: задача – привести в зал ещё раз.

Живёт далеко. Проблема в дороге. Скидка мимо: помогает другой клуб сети поближе к дому или работе, гостевой доступ во все точки. Если сеть одна – честно предложить заморозку вместо ухода.

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

Ходит часто. Он уже лоялен. Ему предлагаем годовой абонемент со скидкой: клиенту выгодно, клуб получает деньги вперёд и снижает риск в разы. По сути это апсейл под видом удержания.

Годовой от партнёра. Если у такого вырос риск – случилось что-то серьёзное. Здесь нужен личный звонок и выяснение причины, а не оффер.

Отдельная находка: доптраты в кафе и на массаж – признак вовлечённости. Кто тратит в клубе, уходит реже. Поэтому для средних портретов часто выгоднее бонус на доптраты, чем скидка на абонемент: клубу дешевле, а клиента втягивает глубже.

Результат

0,97ROC-AUC модели
×8,1концентрация оттока в верхних 10%
15дней – горизонт предупреждения

Подробный разбор с калькулятором потерь – на странице услуги.

Стек

PythonCatBoostpandasscikit-learn снапшоты без утечкиout-of-time валидация выгрузка в CRMголосовой обзвон

Грабли, на которые наступил

Первая модель показала 0,96 и оказалась пустышкой. Признак «дней до конца абонемента» забрал 90% важности – модель просто считала дни до окончания контракта. Формально утечки не было, но история получалась бессмысленная: такое и без машинного обучения видно в календаре. Пришлось переделать генерацию данных так, чтобы поведенческий уход не совпадал с датой окончания абонемента – в жизни человек перестаёт ходить задолго до того, как кончится оплаченный период.

Горизонт 60 дней оказался бесполезен. Начинал с двух месяцев, как принято в подписочных сервисах. Для фитнеса это мимо: клиент с месячным абонементом весь живёт 30 дней, предупреждать за 60 – всё равно что предсказывать погоду на прошлой неделе. Сократил до 15 дней – и точность выросла, и список стал рабочим: «звонить сегодня», а не «когда-нибудь».

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

Телефон есть не у всех. В данных 10% клиентов без контакта. На отток это почти не влияет, но для обзвона критично: бот их не наберёт. Это признак не риска, а достижимости – и он требует отдельного процесса.

Вопросы и ответы

Данные настоящие?

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

Сколько данных нужно?

Год истории. Обязательно вместе с ушедшими – без примеров ухода учиться не на чем. Персональные данные не нужны: имена и телефоны заменяются номерами.

А если клуб не ведёт учёт посещений?

Модель будет работать, но предупреждать позже. Платежи дают базовый сигнал – приближение конца абонемента, история продлений. Журнал визитов добавляет главное: спад активности, который начинается за недели до решения уйти.

Что с сетью из нескольких клубов?

Учим одну модель на всей сети, а решения принимаем по каждому клубу отдельно. Клуб на 2000 человек даёт слишком мало событий, чтобы обучать отдельную модель, но различия между точками модель учитывает как признак. А списки на обзвон формируются локально – бюджет и персонал у каждого клуба свои.

Как понять, что это вообще сработало?

Только контрольной группой. Часть рисковых клиентов намеренно не обзваниваем и сравниваем отток с теми, кого обработали. Без этого любые цифры – вера, а не измерение.

Сколько это занимает?

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

автор – Семенов Евгений, Forward Deployed Software Engineer
ещё кейсы

Похожие проекты

все кейсы →

Нужен голосовой агент?

Хотите бота, который отвечает на звонки как живой оператор? Расскажите задачу – разберём и подберём архитектуру под неё: где важнее скорость, где голос, где цена.

Обсудить задачу
статьи по теме

Разобрано в блоге

все статьи →