Как я приручил ML для HR-аналитики, не будучи дата-сайентистом: кейс по массовому подбору на Avito

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

В массовом подборе (там, где нужны синие воротнички: курьеры, склад, производство, вахта и тд) - сегодня спрос на специалистов в России значительно превышает предложение. Бизнесу нужны люди в полях, а не эти ваши маркетологи. При этом наиболее конверсионной площадкой для масс-найма является не привычный HeadHunter и тем более не LinkedIn (к тому же заблокированный на территории РФ с 2016 года), а Avito. Именно там сейчас быстрее всего закрываются массовые вакансиии.

Как я приручил ML для HR-аналитики, не будучи дата-сайентистом: кейс по массовому подбору на Avito

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

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

Зачем бизнесу нужна HR-аналитика

Ключевая проблема массового найма - слепые зоны. Мы видим количество откликов, но далеко не всегда можем точно и вовремя определить причины происходящего. Почему в одном городе специалист закрывается за две тысячи рублей, а в соседнем - за двадцать? Где именно начинается просадка: в трафике, в конверсии или в самом объявлении?

Именно для ответов на все эти вопросы и была собрана система. Она не объясняет "почему" сама по себе, но позволяет точно увидеть, где начинается просадка. За счёт сравнения объявлений между собой становится понятно, в чём именно проблема: не хватает трафика, падает конверсия или объявление ведёт себя хуже аналогичных вакансий в том же городе и формате. Система сводит эти различия в одни и те же метрики и убирает необходимость разбирать всё вручную. В результате слепые зоны сокращаются не за счёт предположений, а за счёт прямого сравнения данных.

Важно отметить: хотя проект реализован на массовом подборе, где данных много и они достаточно шумные, та же архитектура хорошо ложится и на точечный найм. В частности, в IT - на оценку вовлечённости, рисков выгорания и предсказание увольнений сотрудников. В меньшей степени подход применим к анализу метрик производительности команд, но и там он может быть полезным. Глобально - я просто иду к своей цели реализовать data-driven систему для hr-функции в целом.

Техническая реализация: оркестрация в n8n

Воркфлоу проекта в n8n
Воркфлоу проекта в n8n

Для сбора и анализа данных я выбрал self-hosted n8n. Это позволило собрать гибкий аналитический конвейер без привязки к дорогим SaaS-решениям и с полным контролем над логикой обработки данных.

Через Postgres-ноду система получает список активных API-ключей аккаунтов Avito, что позволяет масштабировать решение на любое количество кабинетов. В моём случае система стабильно работает с десятью аккаунтами, но архитектурных ограничений здесь нет.

Далее n8n обращается к Avito API, получает access-токены и в цикле выкачивает список всех активных объявлений. По каждому объявлению запрашивается детальная статистика за выбранный период (в моем случае - последний месяц).

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

Официальная информация по API от Авито
Официальная информация по API от Авито

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

Внутри n8n через JavaScript-ноды рассчитываются производные показатели - в первую очередь конверсия откликов (CR) и сводная оценка качества объявления (Health Score). Эти метрики позволяют оценивать эффективность вакансий в динамике, а не только по абсолютным значениям. Если конверсия падает ниже пороговых значений для конкретного региона, система фиксирует это как зону риска ещё до того, как проблема становится заметной в общей воронке.

ML без Data Science: кластеризация вместо догадок

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

Я использовал базовые методы машинного обучения, не будучи data scientist’ом и не строя сложных моделей. В основе решения лежит кластеризация KMeans. Алгоритм группирует объявления по совокупности числовых признаков: зарплата, просмотры, отклики, конверсия и производные метрики. В результате вакансии сами раскладываются на группы с похожим поведением.

Как я приручил ML для HR-аналитики, не будучи дата-сайентистом: кейс по массовому подбору на Avito

Это позволяет анализировать не отдельные объявления, а типы объявлений: какие из них стабильно работают, а какие системно показывают слабый результат в конкретном городе и формате вакансии.

Перед кластеризацией данные нормализуются, чтобы алгоритм сравнивал объявления корректно. Иначе большие абсолютные значения (например, тысячи просмотров) - просто задавили бы остальные параметры. Нормализация позволяет смотреть не на размер цифр, а на их качество.

За счёт этого хорошо проявляются аномалии: ситуации, когда объявление ведёт себя нетипично - например, просмотров много, а откликов подозрительно мало. Это прямой сигнал о проблеме: либо в самом объявлении, либо в условиях, либо дальше по цепочке, на этапе обработки откликов.

Health Score как сводный индикатор

Health Score в дашборде. 
Health Score в дашборде. 

Я реализовал ключевую метрику - Health Score. Это агрегированная оценка состояния объявления, которая собирает разрозненные показатели в один понятный индикатор.

В основе Health Score лежит несколько факторов. Главный - конверсия откликов: если люди смотрят объявление, но не откликаются, это почти всегда признак проблемы. Также учитывается объём трафика: объявление с высокой конверсией и десятью просмотрами - не то же самое, что объявление с устойчивым потоком показов.

Отдельно учитывается факт указания зарплаты. Это простой, но стабильный поведенческий фактор: объявления с понятной вилкой почти всегда выигрывают по откликам, и Health Score это отражает. Все сигналы взвешиваются и сводятся в единую шкалу от 0 до 100.

Низкий Health Score означает, что объявление либо плохо конвертирует трафик, либо не получает его в достаточном объёме, либо сочетает в себе оба фактора. Высокий - что объявление стабильно выполняет свою задачу и не требует срочного вмешательства.

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

Ценность подхода в том, что для него не требуется полноценная data science-команда. Здесь машинное обучение - это рабочий инструмент, который заменяет догадки и ускоряет принятие решений на основе данных.

Коллаборация и UI: интерактивная аналитика в Google Colab

Неожиданно для меня самым сложным этапом проекта оказалась не сборка данных и даже не ML-кластеризация, а визуализация результатов. Возник простой вопрос: где всё это показывать?

Таблицы изначально виделись мне плохим вариантом - для анализа динамики и паттернов они быстро перестают быть удобными. Looker Studio от Google показался перегруженным и тяжёлым для быстрого прототипирования, аналог от Яндекса я отбросил почти сразу (по личным соображениям, хоть он и удобнее того же лукера). Разворачивать собственный дашборд с фронтендом и серверной частью - отдельный проект, на который у меня не было ни времени, ни ресурса.

Решением стала Google Colab

Как я приручил ML для HR-аналитики, не будучи дата-сайентистом: кейс по массовому подбору на Avito

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

Технически схема выглядит так: финальный выход аналитического конвейера в n8n настроен на Google Sheets. Туда выгружаются очищенные данные, рассчитанные метрики, Health Score и результаты кластеризации, а Colab используется как интерфейс поверх этих данных.

В ноутбуке реализован UI на ipywidgets. Пользователь может запускать пересчёт кластеров, переключаться между срезами данных и управлять параметрами анализа без правок кода. Для визуализации используется Plotly, что позволяет интерактивно смотреть на распределение вакансий, кластеры и динамику метрик.

Пузырьковые диаграммы

Всего их 4 штуки: конверсия, деньги, заголовки и Health Score + встроенный в каждый график вызываемый инспектор.

CR (Conversion Rate) показывает, какая доля просмотров превращается в отклики.

Как считается: для каждой вакансии берём Applies (отклики) и Views (просмотры) и считаем CR = Applies / Views. 
CR (Conversion Rate) показывает, какая доля просмотров превращается в отклики. Как считается: для каждой вакансии берём Applies (отклики) и Views (просмотры) и считаем CR = Applies / Views. 
Money Impact показывает, насколько зарплата связана с конверсией (CR) внутри однородного кластера. в каждом кластере сравниваем вакансии по salary_avg и их CR (CR = отклики / просмотры). 
Money Impact показывает, насколько зарплата связана с конверсией (CR) внутри однородного кластера. в каждом кластере сравниваем вакансии по salary_avg и их CR (CR = отклики / просмотры). 
Title Score - оценка качества заголовка. Заголовок анализируется автоматически (NLP) и получает балл 0–100. Чем выше балл, тем больше в заголовке смысловых крючков и конкретики; чем ниже - тем он более общий/нейтральный.
Title Score - оценка качества заголовка. Заголовок анализируется автоматически (NLP) и получает балл 0–100. Чем выше балл, тем больше в заголовке смысловых крючков и конкретики; чем ниже - тем он более общий/нейтральный.
 Health Score объединяет несколько факторов: CR (основной вклад), количество откликов, количество просмотров и факт наличия указанной зарплаты. Все компоненты нормализуются и сводятся в шкалу 0–100.
Health Score объединяет несколько факторов: CR (основной вклад), количество откликов, количество просмотров и факт наличия указанной зарплаты. Все компоненты нормализуются и сводятся в шкалу 0–100.
В каждой схеме есть возможность ткнуть на любой пузырек и получить подробную информация о вакансии. Фича называется - "инспектор".
В каждой схеме есть возможность ткнуть на любой пузырек и получить подробную информация о вакансии. Фича называется - "инспектор".

Аналитика по городам

Сводка по городам: просмотры, отклики, CR (отклики/просмотры) и средний Health. Показаны города с достаточным объёмом данных, чтобы убрать шум.
Сводка по городам: просмотры, отклики, CR (отклики/просмотры) и средний Health. Показаны города с достаточным объёмом данных, чтобы убрать шум.

Отдельный срез в системе - аналитика по городам. Таблица агрегирует данные по всем объявлениям внутри каждого города и показывает усреднённую картину найма по ключевым метрикам.

По каждому городу выводятся средние значения просмотров, откликов, конверсии и Health Score, а также медианная или средняя зарплата по активным вакансиям. За счёт этого города становятся сопоставимыми между собой - не на уровне отдельных объявлений, а на уровне общей эффективности найма.

Читать эту таблицу стоит не по одной метрике, а в связке. Высокая зарплата при низком Health Score обычно означает перегретый рынок или неудачную упаковку вакансий. Низкая конверсия при нормальном трафике - сигнал, что объявления в этом городе требуют доработки. Наоборот, города с умеренной зарплатой и высоким Health Score часто указывают на потенциал для более дешёвого и стабильного найма.

Heatmap корреляций

Как я приручил ML для HR-аналитики, не будучи дата-сайентистом: кейс по массовому подбору на Avito

Это инструмент для проверки очевидных и неочевидных связей между метриками. Он показывает, какие показатели действительно связаны между собой, а какие просто кажутся важными.

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

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

Практическая ценность heatmap в том, что она быстро снимает ложные гипотезы. Например, высокая зарплата может слабо коррелировать с конверсией, но сильно - с количеством просмотров. Или рост трафика может почти не влиять на Health Score, если конверсия при этом не растёт. Такие вещи сложно увидеть в таблицах, но на тепловой карте они становятся очевидными.

В итоге heatmap корреляций используется не для отчётов, а для проверки решений. Прежде чем менять условия, повышать зарплаты или масштабировать трафик, можно посмотреть, какие метрики в реальности связаны с эффективностью найма, а какие - нет.

Комплексно - дашборд делает возможным в реальном времени видеть, где эффективность объявлений падает, а где, наоборот, сохраняется потенциал для более дешёвого найма. Всё это - без отдельного фронтенда, серверов и сложной поддержки.

Итог

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

Сегодня предприниматель или системный HR-менеджер может самостоятельно собрать рабочий аналитический контур, адаптированный под свои процессы, а не под ограничения коробочного продукта. Это не отменяет экспертизу специалиста - наоборот, убирает рутину и освобождает время для работы с причинами, а не с цифрами.

Если вам близка такая логика работы с данными, и вы не хотите оставаться в узких рамках принятых сейчас концепций, если вы бизнес или HR и хотите у себя так же - буду рад обсудить похожие подходы, ограничения и практические кейсы в комментариях или личных сообщениях.

Мой тг со статьями, разборами и технологиям:

1 комментарий