Интерактивные и масштабируемые информационные панели с Vaex и Dash

авторы: Йован Вельяноски, Маартен Бредделс

📌 Узнайте, как реализовать машинное обучение для больших данных с помощью Dash & Vaex, на специальном веб-семинаре в режиме реального времени в среду, 26 августа, в 14:00 по восточноевропейскому времени.

Дело в дашбордах…

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

Просто используйте Dash!

Dash - это библиотека Python с открытым исходным кодом для создания веб-приложений.
Созданная на основе React.js, Plotly.js и Flask, она идеально подходит для быстрой разработки
высококачественные, готовые к производству интерактивные информационные панели. Python API аккуратно обертывает множество компонентов React.js, которые можно соединить вместе с различными визуализациями Plotly.js для создания потрясающих веб-приложений. Это может быть мощным инструментом для специалистов по данным, позволяющим им ясно и эффективно передавать историю своих данных без необходимости быть экспертами в интерфейсных технологиях или веб-разработке.

А как насчет… больших наборов данных?

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

Чтобы преодолеть эту проблему, специалисты по данным могут использовать Vaex, библиотеку DataFrame с открытым исходным кодом на Python, специально разработанную с нуля для работы с данными размером с жесткий диск. Он использует отображение памяти, что означает, что не все данные должны помещаться в ОЗУ одновременно. Отображение памяти также позволяет использовать одну и ту же физическую память для всех процессов. Это очень полезно для Dash, который использует рабочих для вертикального масштабирования и Kubernetes для горизонтального масштабирования. Кроме того, Vaex реализует эффективные, полностью распараллеленные алгоритмы вне ядра, которые заставят вас забыть, что вы с самого начала работали с большим набором данных. API внимательно следует за основами, заложенными Pandas, поэтому с ним можно чувствовать себя как дома.

Насколько быстро Vaex на самом деле?

В этой статье Джонатан Александер использует набор данных более 1 000 000 000 (да, более миллиарда!) Строк для сравнения производительности Vaex, PySpark, Dask DataFrame и других библиотек. используется для работы с очень большими наборами данных - на одной машине. Он обнаружил, что Vaex постоянно быстрее, иногда более чем в 500 раз, по сравнению с конкурентами.

Еще одно важное преимущество при использовании Vaex заключается в том, что вам не нужно настраивать кластер или управлять им. Просто запустите pip install vaex, и все готово.

Dash & Vaex

Vaex - идеальный помощник Dash для создания простых, но мощных интерактивных аналитических панелей мониторинга или веб-приложений. Приложения, созданные с помощью Dash, являются реактивными. Когда пользователь нажимает кнопку или перемещает ползунок, например, один или несколько обратных вызовов запускаются на сервере, который выполняет вычисления, необходимые для обновления приложения. Сам сервер не имеет состояния, поэтому он не сохраняет в памяти какое-либо взаимодействие с пользователем. Это позволяет Dash масштабироваться как по вертикали (добавляя больше рабочих), так и по горизонтали (добавляя больше узлов). В некотором смысле Vaex имеет похожие отношения со своими данными. Данные живут на диске и неизменяемы. Vaex также достаточно быстр, чтобы работать без отслеживания состояния, что означает, что фильтрация и агрегирование могут выполняться для каждого запроса без изменения или копирования данных. Результаты любых вычислений или группирования по группам достаточно малы, чтобы их можно было использовать в качестве основы для визуализаций, поскольку их нужно будет отправлять в браузер.

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

В этой статье мы покажем, как любой может создать полностью интерактивное веб-приложение, основанное на наборе данных, который едва помещается в оперативную память на большинстве машин (12 ГБ). Мы будем использовать Vaex для всех манипуляций с данными, агрегирования и статистических вычислений, которые затем будут визуализированы и сделаны интерактивными с помощью Plotly и Dash.

Чтобы узнать больше об основах Dash, прочтите руководство в документации. Страницы документации Vaex также содержат подробное руководство и ряд примеров.

Давайте начнем

Общедоступность, сопоставимость и размер сделали набор данных New York Taxi де-факто стандартом для сравнительного анализа и демонстрации различных подходов к управлению большими наборами данных. В следующем примере используются данные компании YellowCab Taxi за полный год с момента их расцвета, насчитывая более 100 миллионов поездок. Мы использовали Plotly, Dash и Vaex в сочетании с данными такси для создания интерактивного веб-приложения, которое информирует потенциальных пассажиров о вероятной стоимости и продолжительности их следующей поездки, в то же время предоставляя руководителям таксомоторных компаний представление о некоторых общих тенденциях. .

Попробуйте вживую!

Если любопытство берет верх, пройдите по этой ссылке, чтобы опробовать приложение! Полный код доступен на GitHub. Если вас интересует, как были подготовлены данные и как получить их для себя, прочтите через этот блокнот.

Простой, но информативный пример

Чтобы дать представление о том, как вы также можете создать быструю панель управления, используя данные, которые с трудом умещаются в памяти с помощью Dash и Vaex, давайте рассмотрим пример, который подчеркивает основные моменты.

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

В дальнейшем мы предполагаем, что у вас есть разумное знакомство с Dash, и не будем раскрывать все мельчайшие детали, а обсудим наиболее важные концепции.

Начнем с импорта соответствующих библиотек и загрузки данных:

Обратите внимание, что размер файла данных не имеет значения. Vaex мгновенно отобразит данные в памяти и прочитает их в специально запрошенных частях только при необходимости. Кроме того, как это часто бывает с Dash, если запущено несколько рабочих процессов, каждый из них будет использовать одну и ту же физическую память файла с отображением памяти - быстро и эффективно!

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

Следующим шагом является настройка приложения Dash с простым макетом. В нашем случае это основные компоненты, которые следует учитывать:

  • Компонентная часть «панели управления», которая позволяет пользователю выбирать поездки в зависимости от времени dcc.Dropdown(id='days') и дня недели dcc.Dropdown(id='days');
  • Интерактивная карта dcc.Graph(id='heatmap_figure');
  • Результирующие визуализации, основанные на вводе пользователя, будут распределениями затрат и продолжительности поездки, а также блоком уценки, показывающим некоторую ключевую статистику. Компоненты: dcc.Graph(id='trip_summary_amount_figure'), dcc.Graph(id='trip_summary_duration_figure') и dcc.Markdown(id='trip_summary_md').
  • Несколько dcc.Store() компонентов, которые отслеживают состояние пользователя на стороне клиента. Помните, что сам сервер Dash не имеет состояния.

А теперь поговорим о том, как заставить все работать. Мы делим наши функции на три группы:

  • Функции, которые вычисляют соответствующие агрегаты и статистику, которые являются основой для визуализаций. Мы ставим перед ними префикс compute_;
  • Функции, которые обеспечивают эту агрегацию, создают визуализацию, отображаемую на панели инструментов. Мы ставим перед ними префикс create_figure_;
  • Функции обратного вызова Dash, которые украшены хорошо известным декоратором обратного вызова Dash. Они реагируют на изменения от пользователя, вызывают функцию вычисления и передают свои выходные данные функциям создания фигур.

Мы обнаружили, что разделение функций на эти три группы упрощает организацию функциональности приборной панели. Кроме того, это позволяет нам предварительно заполнить приложение, избегая срабатывания обратного вызова при начальной загрузке страницы (новая функция в Dash v1.1!). Да, мы собираемся выжать из этого приложения максимум производительности!

Начнем с расчета тепловой карты. Первым шагом является выбор соответствующего подмножества данных, которые пользователь мог указать с помощью элементов Range Slider и Dropdown, которые управляют часом и днем ​​недели получения, соответственно:

В приведенном выше блоке кода мы сначала делаем неглубокую копию DataFrame, поскольку мы собираемся использовать выборки, которые являются объектами с отслеживанием состояния в DataFrame. Поскольку Dash является многопоточным, мы не хотим, чтобы пользователи влияли на выбор друг друга. (Примечание: мы также можем использовать фильтрацию, например, ddf = df[df.foo > 0], но Vaex обрабатывает выборки немного иначе, чем фильтры, что дает нам еще один прирост производительности). Сам выбор сообщает Vaex, какие части DataFrame следует использовать для любых вычислений, и был создан на основе выбора пользователя.

Теперь мы готовы вычислить данные тепловой карты:

Все методы Vaex DataFrame, такие как .count(), полностью распараллелены и вне ядра, и могут применяться независимо от размера ваших данных. Чтобы вычислить данные тепловой карты, мы передаем два соответствующих столбца через аргумент binby методу .count(). При этом мы подсчитываем количество выборок в сетке, заданной этими осями. Сетка дополнительно определяется ее shape (т. Е. Количеством ячеек на ось) и limits (или экстентом). Также обратите внимание на array_type="xarray" аргумент .count(). При этом мы указываем, что на выходе должен быть массив данных xarray, который, по сути, является массивом numpy, в котором помечено каждое измерение. Как мы скоро увидим, это может быть очень удобно для построения графика. Следите и за этим декоратором. Мы объясним его цель в следующих нескольких абзацах.

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

В приведенной выше функции мы используем Plotly Express для создания реальной тепловой карты с использованием данных, которые мы только что вычислили. Если указаны координаты trip_start и trip_end, они будут добавлены к рисунку как отдельные кривые plotly.graph_objs.Scatter.

Сюжетные фигуры интерактивны по своей природе. Они уже созданы таким образом, что могут легко фиксировать такие события, как масштабирование, панорамирование и щелчки.

Теперь давайте настроим первичный обратный вызов Dash, который будет обновлять рисунок тепловой карты в зависимости от любых изменений в выборке данных или изменений в представлении карты:

В приведенном выше блоке кода мы определяем функцию, которая будет запускаться при изменении любого из значений Input. Затем сама функция вызовет compute_heatmap_data, который вычислит новую агрегацию с учетом новых входных параметров и использует этот результат для создания нового рисунка тепловой карты. Установка аргумента prevent_initial_call декоратора предотвращает вызов этой функции при первом запуске панели управления.

Обратите внимание, как compute_heatmap_data вызывается, когда update_heatmap_figure запускается при изменении trip_start или trip_end, даже если они не являются параметрами compute_heatmap_data. Избегать таких ненужных вызовов и есть цель декоратора, прикрепленного к compute_heatmap_data. Хотя есть несколько способов избежать этого (мы исследовали многие), мы, наконец, остановились на использовании библиотеки flask_caching, как рекомендовано Plotly, для кэширования старых вычислений на 60 секунд - быстро, легко и просто.

Чтобы фиксировать взаимодействия пользователя с тепловой картой, такие как панорамирование и масштабирование, мы определяем следующий обратный вызов Dash:

Захват и реакция на события кликов обрабатывается обратным вызовом this Dash:

Обратите внимание, что обе вышеуказанные функции обратного вызова обновляют ключевые компоненты, необходимые для создания самой тепловой карты. Таким образом, всякий раз, когда обнаруживается событие щелчка или реле (панорамирование или масштабирование), обновление ключевых компонентов запускает обратный вызов update_heatmap_figure, который, в свою очередь, обновляет рисунок тепловой карты. С помощью вышеупомянутой функции мы создаем полностью интерактивную фигуру тепловой карты, которую можно обновлять с помощью внешних элементов управления (RangeSlider и раскрывающееся меню), а также путем взаимодействия с самой фигурой.

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

Теперь мы хотим показать некоторые результаты, учитывая ввод пользователя. Мы будем использовать события щелчка, чтобы выбрать поездки, начиная с «исходной» и заканчивая «конечной» точкой. Для этих поездок мы создадим и отобразим распределение стоимости и продолжительности и выделим наиболее вероятные значения для обоих.

Мы можем вычислить все это в одной функции:

Давайте определим вспомогательную функцию для создания фигуры гистограммы с учетом уже агрегированных данных:

Теперь, когда у нас есть все компоненты, пришло время связать их с приложением Dash с помощью функции обратного вызова:

Вышеупомянутая функция обратного вызова «слушает» любые изменения в «панели управления», а также любые новые щелчки по тепловой карте, которые определяют новые точки отправления или назначения. Когда соответствующее событие регистрируется, функция запускается и, в свою очередь, вызывает функции compute_trip_details и create_histogram_figure с новыми параметрами, таким образом обновляя визуализацию.

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

Наконец, чтобы иметь возможность запускать приборную панель, исходный файл должен заканчиваться:

И вот оно: простое, но мощное интерактивное приложение Dash! Чтобы запустить его локально, выполните команду python app.py в своем терминале, при условии, что вы назвали исходный файл app.py и у вас есть данные о такси. Вы также можете просмотреть весь исходный файл через этот GitHub Gist.

Что-то другое

Plotly реализует множество творческих способов визуализации данных. Чтобы показать что-то, кроме типичных тепловых карт и гистограмм, наша полная панель инструментов также содержит несколько информативных, но менее распространенных способов визуализации агрегированных данных. На первой вкладке вы можете увидеть географическую карту, на которой зоны Нью-Йорка окрашены в зависимости от количества поднятых такси. Затем пользователь может выбрать зону на карте и получить информацию о популярных направлениях (зонах и районах) с помощью диаграмм Санки и Санберст. Пользователь также может щелкнуть зону на этих диаграммах, чтобы получить самые популярные направления этой зоны. Создание этой функции следует тем же принципам, что и для вкладки Планировщик поездок, о которой мы говорили выше. Ядро его вращается вокруг операций groupby, за которыми следуют некоторые манипуляции для преобразования данных в формат, необходимый для Plotly. Это быстро и красиво! Если вас интересуют подробности, вы можете увидеть код здесь.

Представление

Вы можете задаться вопросом, сколько пользователей может обслуживать наша полная панель управления одновременно? Конечно, это немного зависит от того, что делают пользователи, но мы можем дать некоторые цифры, чтобы получить представление о производительности. При изменении зоны на географической карте (окно choroplethmap), когда не выбраны часы или дни, мы можем выполнять 40 вычислений (запросов) в секунду или 3,5 миллиона запросов в день. Самые дорогие операции происходят при взаимодействии с тепловой картой Планировщика поездок с выбором часов и дней. В этом случае мы можем обслуживать 10 запросов в секунду или 0,8 миллиона запросов в день.

То, как это приводит к одновременному количеству пользователей, во многом зависит от их поведения, но обслуживание 10–20 одновременных пользователей не должно быть проблемой. Если предположить, что пользователи остаются на месте в течение минуты и взаимодействуют с панелью мониторинга каждую секунду, это будет означать 14–28 тысяч сеансов в день, исследующих более 120 миллионов строк на одной машине! Не только экономично, но и экологически безопасно.

Все эти тесты выполняются на настольном компьютере AMD 3970X (32 ядра).

Масштабирование: больше пользователей

Вы хотите обслуживать больше пользователей? Поскольку Dash не имеет состояния на стороне сервера, его легко масштабировать, добавляя больше компьютеров / узлов (масштабирование по горизонтали). Любой инженер DevOps должен иметь возможность добавить балансировщик нагрузки перед фермой серверов Dash. В качестве альтернативы можно использовать функцию автомасштабирования Dash Enterprise Kubernetes, которая автоматически увеличивает или уменьшает масштаб ваших вычислений в зависимости от использования. Новые узлы должны быстро разворачиваться, поскольку им требуется только доступ к набору данных. Сам запуск сервера занимает около секунды из-за отображения памяти.

Масштабирование: больше данных

А как насчет панелей мониторинга, показывающих еще большие данные? Vaex может легко обрабатывать наборы данных, состоящие из миллиардов строк! Чтобы продемонстрировать эту возможность, мы также можем использовать указанную выше панель управления с увеличенной версией набора данных о такси Нью-Йорка, который насчитывает более полумиллиарда поездок. Однако из-за затрат на вычисления мы не публикуем эту версию приложения. Если вы хотите попробовать это, обратитесь в Plotly или Vaex.

Пусть говорят ваши данные. Все это.

Комбинация Dash и Vaex позволяет специалистам по обработке данных легко создавать масштабируемые, готовые к производству веб-приложения, использующие довольно большие наборы данных, которые иначе не поместятся в памяти. Благодаря масштабируемости Dash и превосходной производительности Vaex вы можете позволить своим данным рассказать всю историю - всем.