Цены на Uber варьируются в зависимости от спроса и предложения, и я хотел предсказать, какими они будут, чтобы сэкономить время и деньги при его использовании. Иногда я могу подождать 10 минут, и цена снижается вдвое, а иногда я просто жду час без сдачи. Итак, этот проект призван помочь в этом, предсказывая цены, чтобы я знал, сколько времени мне нужно ждать, чтобы получить его. Решения, основанные на данных, будут здесь модным словом.

GitHub: https://github.com/tylerhaun/uber-price-tracker

Обзор

В нем есть несколько разных компонентов. Задание ETL, которое должно выполняться постоянно, чтобы собирать данные о ценах Uber и хранить их в базе данных, клиентский интерфейс для визуализации данных и программа прогнозирования, которая может учиться на собранных данных и иметь возможность выводить цены в будущем. раз.

Задание ETL - это простая программа узла, которая использует node-cron для планирования функции для запуска, которая запрашивает конечную точку оценки стоимости проезда uber, которую я нашел на их основном маркетинговом сайте https://www.uber.com/fare-estimate/ . Конечная точка занимает 2 местоположения, от и до, а затем возвращает цены для каждого типа uber, например, пул, черный X и т. Д. Затем задание ETL преобразует данные и сохраняет их в простой таблице SQLite временных рядов. Большим недостатком этого является то, что вам нужно выполнять разные задания для каждой пары локаций. В моем примере он собирал данные от Санта-Моники до Голливуда, но я хочу поэкспериментировать с другими.

График внешнего интерфейса - это простая диаграмма d3, которую я нашел в сети и улучшил для этого проекта. Я добавил инспектор наведения, похожий на графики Google, где, когда вы наводите курсор на точку на графике, он сообщает вам значения x и y на пересечении y. Он обслуживается с помощью handlebars.js, который вводит данные из базы данных. Поскольку данные становились настолько большими, мне пришлось добавить фильтры даты и типа, а также динамическую понижающую дискретизацию данных с помощью оператора модуля.

(Мне всегда неприятно читать построение SQL). Но в основном добавьте row_number к столбцам, а затем отфильтруйте по row_num% downsampling_factor = 0. Для этого мне нужно было обновить SQLite до последней версии, поскольку ROW_NUMBER () - более новая функция. Коэффициент понижающей дискретизации рассчитывается для возврата количества точек, аналогичных параметру numPointsTarget, поэтому его следует легко настроить для возврата желаемого количества точек.

Для программы прогнозирования я попытался начать с библиотеки node.js synaptic, надеясь, что этого будет достаточно. Поигравшись с ним некоторое время, я получил его частично работающим, но он был смехотворно медленным и не имел некоторых функций, поэтому я решил попробовать python, поскольку я знаю, что он должен быть хорош для науки о данных. Я остановился на керасе, и это неплохо получилось. Был быстрым и имел все функции, которые я хотел, например пакетирование, и гораздо больше, чем я знал, что с ними делать.

Прогнозирование машинного обучения

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

  • Отметка времени UNIX
  • разница между моментом времени и текущим моментом
  • год
  • месяц (1–12)
  • дата (1–31)
  • день (1–7)
  • час (0–23)
  • минута (0–59)
  • второй (0–59)
  • праздники (Рождество, Пасха, День Благодарения)
  • спортивные мероприятия / концерты

В итоге я использовал месяц, дату, день недели, час и минуту, поскольку они казались наиболее важными, как видно из этого фрагмента кода:

Это выводит массив длиной 134 со всем двоичным кодом. Например, часть месяца преобразуется из 1–12 в список логических значений. Примером этого является январь (месяц №1) - ›[1,0,0,0,0,0,0,0,0,0,0,0,0], февраль (месяц №2) -› [ 0,1,0,0,0,0,0,0,0,0,0,0] и т. Д. Я полагал, что этот метод будет лучшим для сети, поскольку он наименее неоднозначен по сравнению с использованием значения месяц (1–12) как один ввод.

Затем, чтобы обучить сеть, вам просто нужно преобразовать время в этот массив и обучить его значению, связанному с ним.

Для нейронных сетей (по крайней мере, тех, которые я видел и использовал), все входы и выходы имеют значения от 0 до 1. Поэтому мне пришлось сопоставить диапазон выходных значений с 0–1. Для этого я создал класс линейного масштабатора, который также имеет инверсию, которая необходима после активации сети на входах для получения цены. Я выбрал 18–30, так как это охватывает все возможные цены, которые я видел до сих пор. Итак, 18->0, 30->1, 14->0.5 и т. Д.

Обучение модели

Для обучения модели потребовалось несколько итераций поиграть со значениями, пока она не стала выглядеть правильно. Модель имеет 3 слоя. Один вход с 134 узлами, один скрытый слой с 2 ​​* 134 = 268 узлами и один выходной слой с 1 узлом, представляющий нормализованную цену. 134 поступает из предыдущей функции времени преобразования во входные данные, и ее следует изменить, если эта функция изменится.

Создание данных прогноза

Для создания данных прогноза просто требуется список дат, значения которых вы хотите, прогонять эти даты через обученную модель, а затем снова масштабировать значение до цены.

Чтобы создать время предсказания, я нашел функцию pandas date_range, которая оказалась полезной. Он дает большой список дат для работы с обученной моделью. Затем сопоставьте эти даты с логическими входными списками, используя ту же функцию преобразования, которая использовалась для обучения модели, пропустите входные данные через нейронную сеть, сопоставьте данные, чтобы они соответствовали столбцам таблицы fare_estimate, и сохраните их в базе данных.

Результат:

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

Выводы / уроки:

Недостатки визуализации данных:

По мере роста данных визуализировать их становится все труднее. Использование понижающей дискретизации просто, но потенциально удаляет важные функции из данных. Усреднение будет таким же. Другие типы графиков могут улучшить его, например, свечной график или лучшая интерактивность.

Недостатки SQLite:

Хотя SQLite - это простой способ хранения данных, который отлично работает для ряда проектов, над которыми я работал, здесь я начал сталкиваться с некоторыми проблемами. У меня было две разные программы, которые пытались получить к нему доступ одновременно, что вызывало ошибки блокировки. Когда задание прогнозирования выполнялось и сохраняло данные в базе данных, что занимало много времени (в некоторых случаях более минуты), интерфейсное приложение было сломано, потому что база данных была полностью заблокирована в течение этого времени. Я никогда раньше не сталкивался с этой проблемой с обычной базой данных (MySQL, Postgres, MongoDB), поэтому я предполагаю, что это SQLite.

Кроме того, я столкнулся с некоторыми проблемами при использовании SQLAlchemy при попытке выполнить массовую вставку. По-видимому, он не поддерживает массовую вставку, поэтому мне приходилось вставлять по одной строке с тысячами записей, поэтому вставка занимала так много времени. Я читал, что вы можете делать транзакционные вставки, которые ускоряют работу, но у меня не было на это времени.

Время:

Мне всегда нравится измерять и проверять время, необходимое для завершения проекта, чтобы оптимизировать его в будущем. Как говорится, время - деньги, поэтому чем быстрее я смогу завершить проекты, тем больше денег я смогу помочь своей компании заработать.

Работа ETL ~ 2 часа

График D3 ~ 5 часов

Нейронная сеть Nodejs ~ 15 часов

нейронная сеть python ~ 18 часов

Задачи, которые я уже хорошо знал, такие как базы данных, модели, конечные точки и API, выполнялись очень быстро, как это видно на примере задания ETL.

С D3 у меня не так много опыта, поэтому большая часть этого времени была потрачена на обучение и эксперименты, пока я не добился того, что все заработало.

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

Затем питон доставлял мне множество проблем и очень волновал меня. Я потратил много времени, пытаясь вставить данные в базу данных SQLite. Я начал с использования обычного модуля sqlite3 и создания запросов вручную, но мне нужно было что-то более надежное, поэтому я начал использовать ORM, такие как peewee и SQLAlchemy. У меня уже были созданы схемы таблиц, и мне нужно было что-то, что могло бы загружать модели из таблицы. Peewee хотел, чтобы я запустил скрипт для базы данных, чтобы создать файлы с моделями в ней, что глупо (на самом деле круто, но не то, что я хотел). Но SQLAlchemy позволил мне автозагрузить схемы из таблицы, которая работала довольно хорошо, поэтому я согласился.

И еще большую часть времени я потратил на то, чтобы заставить свидания работать. У меня проблемы возникали только при использовании модуля datetime в Python. По удобству использования, простоте и функциональности он не сравнится с moment.js. Datetime не имеет встроенных часовых поясов, поэтому вам нужно использовать pytz, чтобы установить его. И поскольку sqlite3 использует все время в формате UTC, мне пришлось создать дату и время, добавить часовой пояс, а затем перейти на UTC.

И все это заняло у меня часы, чтобы понять, что происходит. Может быть, python слишком сложен, а может, использование javascript сделало меня слабым.

И еще одна проблема, на которую я потратил некоторое время, - это то, что SQLAlchemy не сохраняет смещение часового пояса, когда я что-то вставляю. Это было простое исправление, заключающееся в использовании SQLAlchemy для создания оператора с последующей передачей данных в себя.

Так что в будущем я начну с SQLAlchemy, поскольку он кажется наиболее гибким вариантом. Я могу создавать запросы, редактировать и выполнять их сам. И он может получить структуру таблицы из базы данных, что было очень полезно.

Python против JavaScript

Для меня JavaScript по-прежнему №1, но когда дело касается больших данных, Python намного превосходит его. Node.js потратил на обучение моделей на несколько порядков дольше, чем python, и получил худшие результаты. Но заставить питон работать правильно - это головная боль. Возможно, это из-за моей неопытности, но javascript кажется намного проще и интуитивно понятным, плюс есть действительно хорошие инструменты, такие как инспектор инструментов chrome dev.

Я с нетерпением жду того дня, когда JavaScript сможет заниматься наукой о данных, но пока это Python.

Заключение:

В настоящее время в СМИ много шумихи вокруг машинного обучения и ИИ, и я чувствую, что по большей части это просто маркетинг, как это было со многими крупными компаниями, такими как Google и их ИИ, которые могут обнаруживать видео с кошками. Но для этого определенно есть какое-то применение. Этот проект использовал его, чтобы узнать будущие цены на Ubers, что может сэкономить мне деньги и позволяет мне принимать более обоснованные решения. Я вижу, что эта концепция распространяется на множество различных сфер применения и отраслей, помогая компаниям расти и давая им преимущество перед их конкурентами.