Узнайте, как создать интерактивное многоразовое веб-приложение для исследовательского анализа данных с помощью ведущих инструментов визуализации данных Plotly и Streamlit (включая данные и код)

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

Они могут собрать блокнот Jupyter, чтобы просматривать сводки данных, первые несколько строк данных и диаграммы matplotlib. Некоторые могут просматривать данные как лист Excel и работать со сводными таблицами. Те, кто действительно владеет данными, могут даже предпочесть смотреть прямо на необработанную таблицу данных.

Ни одно из этих решений не является идеальным. Некоторые из этих решений могут быть подходящими только для мазохистов среди нас. Так что же делать человеку?

Что касается меня, я предпочитаю создавать веб-приложение для исследования данных.

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

Это позволяет мне взаимодействовать с данными визуально.

В наши дни я предпочитаю использовать для этой задачи Plotly и Streamlit. За последнее время я достаточно написал о Plotly - я считаю, что это лучший пакет визуализации данных для Python. Но Streamlit действительно изменил мою работу. Поскольку он такой краткий, почти не требуется дополнительных усилий, чтобы превратить мои графики и комментарии в скрипте Python в интерактивное веб-приложение, когда я возюсь. (К вашему сведению - я написал сравнение Dash и Streamlit здесь)

Я предпочитаю создавать веб-приложение для исследования данных

В этой статье я хотел бы поделиться простым примером создания приложения для исследования данных с помощью этих инструментов.

Теперь для проекта данных - нам нужны данные, и здесь я буду использовать статистику НБА. Изучение программирования может быть сухим, поэтому использование чего-то связанного, например, спортивных данных, помогает мне оставаться вовлеченным; и, надеюсь, это будет и для вас.

(Не волнуйтесь, если вы не следите за НБА, поскольку основное внимание уделяется науке о данных и программированию!)

Прежде чем мы начнем

Чтобы продолжить, установите несколько пакетов - plotly, streamlit и pandas. Установите каждый (в виртуальной среде) с помощью простого pip install [PACKAGE_NAME].

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

Скрипт называется data_explorer_app.py, поэтому вы можете запустить его из оболочки с помощью:

streamlit run data_explorer_app.py

О, это первая из серии статей по науке о данных / анализу данных, о которых я планирую написать, используя данные NBA. Все пойдет на это репо, так что не спускайте глаз!

Если вы следуете инструкциям, импортируйте ключевые библиотеки с помощью:

import pandas as pd
import plotly.express as px
import streamlit as st

И мы готовы к работе.

Глубокое погружение в данные

Обтекаемый

Здесь мы используем Streamlit, поскольку он разработан, чтобы помочь нам быстро создавать приложения для обработки данных. Итак, мы собираемся создать приложение Streamlit, которое затем будет запускаться локально. (Для получения дополнительной информации вы можете прочитать мою статью Dash v Streamlit здесь.)

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

import streamlit as st
st.write("Hello, world!")

Сохраните это как app.py, а затем выполните его с помощью команды оболочки streamlit run app.py:

И у вас есть работающее веб-приложение! Создать оптимизированное приложение так просто. Но что еще более удивительно, создать полезное приложение не намного сложнее.

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

Просто продолжайте запускать скрипт и нажимайте здесь «Повторить» каждый раз, когда захотите увидеть последнюю версию в действии.

Готовый? Хорошо, пойдем!

Исследование сырых данных

Сначала мне нравится смотреть на весь набор необработанных данных. В качестве первого шага мы загружаем данные из файла CSV:

df = pd.read_csv("data/player_per_game.csv", index_col=0).reset_index(drop=True)

После загрузки данных простой ввод st.write(df) создает динамическую интерактивную таблицу всего фрейма данных.

И различные статистические данные для столбцов могут быть построены аналогичным образом с помощью st.write(df.describe()).

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

Теперь мы готовы начать добавлять несколько диаграмм в наше приложение.

Визуализация распределения

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

Мы начнем анализ с визуализации данных по одной переменной с интерактивной гистограммой. Гистограмма может быть построена с помощью Plotly следующим образом:

hist_fig = px.histogram(df, x=hist_x, nbins=hist_bins)

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

Гистограмма будет анализировать данные из одного столбца фрейма данных pandas. Давайте представим его в виде раскрывающегося списка, вызвав модуль st.selectbox(). Мы можем просто взять список столбцов как df.columns, и дополнительно мы предоставляем выбор по умолчанию, который мы получаем с помощью метода df.columns.get_loc(). Собирая вместе, получаем:

hist_x = st.selectbox("Histogram variable", options=df.columns, index=df.columns.get_loc("mp_per_g"))

Затем можно вызвать ползунок с модулем st.slider(), чтобы пользователь мог выбрать количество интервалов в гистограмме. В модуле можно настроить параметры минимума / максимума / значения по умолчанию и приращения, как показано ниже.

hist_bins = st.slider(label="Histogram bins", min_value=5, max_value=50, value=25, step=1)

Затем эти параметры можно объединить для получения фигуры:

hist_fig = px.histogram(df, x=hist_x, nbins=hist_bins, title="Histogram of " + hist_x,
                        template="plotly_white")
st.write(hist_fig)

Собрав его вместе с небольшим заголовком st.header(“Histogram”), мы получим:

Я рекомендую уделить здесь секунду, чтобы изучить данные. Например, взгляните на разные статистические данные, такие как подборы за игру:

Или должности:

Интерактивность делает более простым, динамичным, активным исследованием данных.

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

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

df[hist_x].sort_values().unique()

В совокупности получаем:

hist_cats = df[hist_x].sort_values().values
hist_fig = px.histogram(df, x=hist_x, nbins=hist_bins, title="Histogram of " + hist_x,
                        template="plotly_white", category_orders={hist_x: hist_cats})

Таким образом, любые категориальные (или порядковые) переменные будут представлены в порядке

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

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

box_x = st.selectbox("Boxplot variable", options=df.columns, index=df.columns.get_loc("pts_per_g"))
box_cat = st.selectbox("Categorical variable", ["pos_simple", "age", "season"], 0)

И для построения фигуры достаточно передать эти два входа в Plotly:

box_fig = px.box(df, x=box_cat, y=box_x, title="Box plot of " + box_x, template="plotly_white", category_orders={"pos_simple": ["PG", "SG", "SF", "PF", "C"]})
st.write(box_fig)

Тогда… вуаля! У вас есть интерактивный коробочный сюжет!

Вы заметите, что я вручную передал заказ для столбца упрощенных позиций. Причина в том, что этот порядок является относительно произвольным, специфичным для баскетбола (от PG до C), а не в алфавитном порядке. Как бы мне ни хотелось, чтобы все было параметрическим, иногда приходится прибегать к ручным спецификациям!

Корреляции и фильтры

Еще одна важная вещь, которую нужно сделать в визуализации данных или исследовательском анализе данных, - это понять корреляции.

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

Давайте пока остановимся на трех измерениях на нашем графике рассеяния.

Нет, не в направлениях x, y и z. Я не монстр. Ниже приведен пример одного из них. Можете ли вы понять, что происходит?

Не для меня, спасибо.

Цвет будет здесь третьим измерением для представления данных. Я оставил все столбцы доступными для первых двух столбцов и лишь ограниченный выбор цветов, но вы действительно можете делать все, что захотите.

corr_x = st.selectbox("Correlation - X variable", options=df.columns, index=df.columns.get_loc("fg3a_per_g"))
corr_y = st.selectbox("Correlation - Y variable", options=df.columns, index=df.columns.get_loc("efg_pct"))
corr_col = st.radio("Correlation - color variable", options=["age", "season", "pos_simple"], index=1)

А диаграмму можно построить следующим образом:

fig = px.scatter(df, x=corr_x, y=corr_y, template="plotly_white", color=corr_col, hover_data=['name', 'pos', 'age', 'season'], color_continuous_scale=px.colors.sequential.OrRd)

Но этот график не идеален. Во-первых, потому что в данных преобладают выбросы. Видите одинокие точки слева вверху? Люди с эффективным FG% 1,5 не являются богами баскетбола, но это побочный эффект чрезвычайно малых размеров выборки.

Так что мы можем сделать? Давайте добавим фильтр к данным.

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

corr_filt = st.selectbox("Filter variable", options=df.columns, index=df.columns.get_loc("fg3a_per_g"))
min_filt = st.number_input("Minimum value", value=6, min_value=0)

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

tmp_df = df[df[corr_filt] > min_filt]

А затем передаем на фигуру временный фрейм данных tmp_df вместо исходного фрейма данных, мы получим:

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

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

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

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

Обобщенные корреляции с тепловыми картами

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

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

Поскольку тепловая карта лучше всего визуализирует корреляции между наборами категорий ввода, давайте воспользуемся вводом, который будет принимать несколько категорий. В результате st.multiselect() является здесь предпочтительным модулем, а df.corr() - все, что нам нужно для создания корреляционной матрицы.

Комбинированный код:

hmap_params = st.multiselect("Select parameters to include on heatmap", options=list(df.columns), default=[p for p in df.columns if "fg" in p])
hmap_fig = px.imshow(df[hmap_params].corr())
st.write(hmap_fig)

И получаем:

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

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

И имейте в виду, что то, что я предложил здесь, - это просто базовые предложения, и я уверен, что вы могли бы создать что-то гораздо более полезное для ваших собственных целей и ваших предпочтений. Я с нетерпением жду встречи с ними всех!

Но перед тем, как уйти - если вам это понравилось, скажите привет / подпишитесь на twitte r или следите за обновлениями. ICYMI: Я также написал эти статьи, которые могут быть вам полезны:







До скорого! Оставайтесь в безопасности :)