История с выбором идеального автомобиля продолжается. Начало: https://zen.yandex.ru/media/id/5c7777a3edb9e500afc06642/kak-data-saentist-iscet-pervyi-avtomobil-5c7777ce3a1fd900b3bd1da3. После того, как была обучена первая модель, я задался вопросом, как ей удобнее всего пользоваться. Не секрет, что есть мобильное приложение 'авто.ру', которое присылает пуши, если на сайте появляются новые автомобили подходящие под критерий вашего поиска. Однако, меня отличает как раз то, что жёстких критерий у меня нет, да и засорять телефон пушами желания нет. Поэтому как источник подачи информации я решил использовать телеграм бота.
На Githubе можно найти множество движков для создания бота. Я выбрал "python-telegram-bot". Среди содержимого репозитория есть множество примеров, как обрабатывать сложные команды, пользоваться "болталкой" и прочее. Логика очень простая. Если пользователь обращается к боту, то тот парсит сообщение и запускает в работу один из скриптов. Под скриптом я имею ввиду последовательную обработку свзяанных между собой сообщений. Решение какую именно функцию запускать в тот или иной момент принимается в зависимости от текущего состояния. Лично мне такая концепция сильно напоминает машину Тьюринга.
Когда бот находится в каком-то из состояний внутри скрипта, то у него имеется доступ к общей памяти(context), которой мы можем пользоваться как словарём. Таким образом можно передавать данные из одной функции и другую.
Итак, когда стало понятно, как создавать бота, то нужно переёти к его наполнению. Моей хотелкой было вот что: чтобы при выборе марки и модели автомобиля, бот присылал мне топ наиболее "горячих" объявлений за последние сутки. Горячесть очень легко вычислить - для каждого свежего объявления мы применяем заранее обученную модель и потом выбираем с самой большой скидкой. Тут есть один хитрый момент - чтобы послучить топ объявлений за сутки я не хочу постоянно парсить информацию с авто.ру. Это лишняя нагрузка на сервер. Поэтому я выбрал период после 0:00, когда автоматически запустится обновление. Запускается обновление при помощи Shedulerа прямо внутри основной функции бота, причём важно, чтобы таймер был асихронным и ничего не блокировал!
Немного уточню про информацию, которая выводится. Что означает строка "- цена в сравнении с другими". Всё очень просто. Первая цифра - реальная цена автомобиля, вторая цифра - это разница между стоимостью, которую предсказала модель и реальной ценой(и в процентном соотношении). Последние две цифры отвечают за разброс модели, диапозон цен в который попадёт данная машина с большой вероятностью. Получены они довльно легко. На том же датасете обучается градиентный бустинг с такими же параметрами, что и осноная модель, однако в качестве функции потерь выбирается Quantile, гду мы при помощи параметра alpha(от 0 до 1) задаём квантиль распределения стоимости, которую мы хотим узнать. Для себя я решил, что по 10% автомобилей снизу и сверху можно отсечь.
С того момента, как я написал первую статью прошло три недели. Можно предположить, что автомобильный рынок изменился, да и саму модель можно сделать более умной. Я обновил мой небольшой датасет, обучил новую модель и заменил ею старую. Однако, хороший аналитик помимо обучения модели хочет задаться вопросом: а что изменилось за три недели? Было решено провести мини-исследование.
Во-первых, распределение различных моделей автомобилей. Как видно из графика, то объявлений стало в разы меньше, особенно заметно с Фокусами(но там скорее аномалия).
Во-вторых, распределение автомобилей по дате производства(аналог возраста). С одной стороны, если не принимать во внимание общее уменьшение числа автомобилей, то они похожи, но всё-таки в новых данных распределение смещено к 2020 году. Это легко объясняется теми же фокусами, которые несколько лет не продаются в России(т.е. старые авто с большим пробегом). Для более точного анализа можно было бы данную картинку привести действительно к графику плоности, нормировав на общее число автомобилей. Затем, посчитать простые статистики, как среднее и квартили. Ещё одной мерой, которой можно было бы воспользоваться - расстояние Вассерштайна. Но я решил этого не делать.
Как можно предположить, если выбор скоратился, то цены должны вырасти. И это действительно так! Однако как измерить изменение цен? Ведь распределение автомобилей сильно поменялось. На этот вопрос нам помогут ответить наши модели машинного обучения. Одна из них обучалась на старом датасете, другая на новом. К сожалению, сравнивать каждое дерево градиентного бустинга смысла нет. Методы анализа важности признаков тоже не подходят. Это лишь показатели того, как изменилось распределение. Поэтому я пришёл к такому методу - сравнивать не сами модели, а то, как они предсказывают. Для этого желательно иметь датасет, на котором будут проверяться модели. Он не может быть частью датасета из обучения. И ещё хотелось бы, чтобы он был "идеальным" и покрывал все марки, кузова, двигатели и прочее. Каждой твари по паре. Но в тоже время если создать такой искуственный датасет, то нет никакой гарантии, что сравнение на нём будет являться репрезентативным. Потому что признаки распределены совсем не так как в реальной жизни! Ответ прост. Датасет, который обновляется ежедневно!
Оказывается, что более свежая модель предсказывает актуальные цены точнее. Среднеквадратичная ошибка на 10% ниже, но это не значит, что модель точнее на 10%. Для меня было интересно сравнить распределения разностей между предсказаниями и реальными ценами. На глаз раницы особо нет... И, конечно, можно просто посмотреть на основные статистики - среднюю и медианную стоимости. Заметно, что свежая модель гораздо ближе к реальности и по среднему значению на 0.12% предсказывает больше предыдущей. И гораздо выше разница если взять медианную стоимость(полагаю, что большинство автомобилей без дтп и с одним владельцем попадают именно туда) - рост цен уже 0.85%. Всего за три недели. В итоге мы получили явный признак того, что автомобиль надо будет поискать попозже, когда станет больше предложений и, возможно, упадут цены.
Вот так можно познакомиться с ботом. Предупреждаю, что он пока не рассчитан на публичное использование:)
А вот ссылка на гит:) Спасибо за прочтение!