Герман Дьяков
Герман Дьяков Аналитик данных · Санкт-Петербург / удалённо

Как отличить живого читателя от бота

Меня зовут Герман Дьяков, я аналитик данных. Ко мне пришла задача в той формулировке, в которой такие задачи обычно и приходят: «базу засыпало регистрациями, надо почистить, но живых читателей терять нельзя». База научно-популярного портала — около 121 тысячи аккаунтов. Ниже — не рассказ про модель, а разбор того, что в этой задаче оказалось важнее модели.

121 000аккаунтов в исходной базе 2,5%доля положительного класса — базовый уровень внедреносписок передан владельцу, база дочищена

Откуда взялась разметка

Готовых меток «бот / человек» не было. Разметку я собрал из разности двух снимков базы: часть аккаунтов между выгрузками исчезла — их удалили при ручной чистке. Это и стало положительным классом. Такая разметка бесплатна, но она не идеальна, и позже это выстрелило.

Почему первая версия с качеством 0,99 была бесполезной

Первая модель показала почти идеальное качество. Разбор показал, за счёт чего: она выучила дату регистрации. Боты пришли волной, живые пользователи размазаны по годам — и дата почти идеально разделяла классы сама по себе. То есть модель отвечала не на вопрос «бот или человек», а на вопрос «когда зарегистрирован». На новых регистрациях, где после определённого момента находятся все, она была бы бесполезна.

Я пересобрал задачу на сопоставимом временном окне, где обе группы присутствуют одновременно. Метрика упала до честной — PR-AUC около 0,59 при базовом уровне 0,025 — зато стала что-то значить.

Почему порог не 0,5

Ошибки здесь несимметричны. Удалить живого читателя — необратимо: человек не узнает, что его удалили, и не вернётся. Оставить бота — поправимо: он попадёт в следующую чистку. Поэтому порог выбирался не по умолчанию, а по таблице «сколько живых теряем против скольких ботов ловим» — и решение принимал владелец базы, а не метрика.

Устойчивость во времени

Отдельно проверил, не разъезжаются ли данные между периодами. По числовым признакам сдвиг оказался незначительным, а вот по источнику регистрации — сильным: PSI ≈ 0,83, около 600 новых доменов, затрагивающих 8% аккаунтов. Это значит, что признак «домен» нельзя считать стабильным и модель придётся периодически переобучать.

Что показал разбор ошибок

Самое интересное было в конце. Часть «ложных срабатываний» — аккаунтов, которые модель назвала ботами, а разметка считала живыми — при ручной проверке оказалась ботами, которых пропустили при первой чистке. То есть модель упёрлась в потолок качества разметки, а не собственного. Список ушёл владельцу базы, по нему базу дочистили.

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

Смотреть дальше