Python

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

Раньше для демонстрации проекта хватало хороших визуализаций или небольших PPT, однако с появлением таких инструментов для создания дашбордов, как RShiny и Dash, хорошему специалисту по данным стало необходимо разбираться в веб-фреймворках. 

Веб-фреймворки трудно освоить. Я до сих пор путаюсь в HTML, CSS и Javascript, когда нужно создать даже что-то простое. И я уже не говорю о таком большом разнообразии способов выполнить одну и ту же задачу. Просто кошмар для специалистов по работе с данными, для которых веб-разработка — второстепенный навык.

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

И вот здесь на помощь приходит Streamlit с возможностью создавать веб-приложения на Python. 

Дзен Python: Простое лучше, чем сложное, и Streamlit предельно упрощает создание приложений. 

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

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

Установка

Устанавливаем Streamlit — просто запускаем команду: 

pip install streamlit

Проверяем, что установка прошла успешно: 

streamlit hello

Эта команда выведет следующее сообщение на экран: 

Пройдите по локальному URL localhost:8501 в браузере, чтобы увидеть приложение Streamlit в действии. Разработчики предоставили несколько классных демо, с которыми можно поиграть. Прежде чем вернуться к коду, уделите приложению немного времени, чтобы почувствовать пользу инструментов. 

Hello World в Streamlit

Цель Streamlit — упростить разработку приложений с помощью Python.

Давайте напишем простое приложение, чтобы проверить, справится ли Streamlit с задачей.

Начнем с приложения, которое назовем Hello World. Просто поместим код ниже в файл helloworld.py:

import streamlit as st

x = st.slider('x')
st.write(x, 'squared is', x * x)

И запустим файл в терминале: 

streamlit run helloworld.py

Вуаля, вы увидите это приложение в действии в браузере по адресу localhost:8501, оно позволяет вам двигать ползунок и выдает результат. 

Простое приложение с виджетом ползунка

Это было очень просто. В приложении выше мы использовали две фичи Streamlit:

  • виджет st.slider, который можно двигать и менять вывод веб-приложения;
  • универсальную команду st.write. Мне нравится, как она записывает данные из таблиц, наборов данных и простого текста. Подробнее об этом позже. 

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

Виджеты Streamlit 

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

1. Ползунок

streamlit.slider(label, min_value=None, max_value=None, value=None, step=None, format=None)

Выше мы уже видели st.slider в действии. Его можно использовать с min_value, max_value и step для получения выходных данных в диапазоне.

2. Ввод текста

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

import streamlit as st

url = st.text_input('Enter URL')
st.write('The Entered URL is', url)

Вот как выглядит приложение: 

Простое приложение с виджетом ввода текста

Подсказка: Можно просто заменить файл helloworld.py и обновить браузер. Я открываю и изменяю helloworld.py в редакторе Sublime text и вижу изменения в браузере рядом.

3. Чекбокс

Один вариант использования чекбокса — скрыть или показать определенную область в приложении. Другой — задать булевое значение в параметрах для функции. st.checkbox() принимает один аргумент — лейбл виджета. 

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

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")
if st.checkbox('Show dataframe'):
    st.write(df)
Простое приложение с виджетом чекбокса

4. SelectBox

Мы можем использовать st.selectbox для выбора из серии или списка. Обычный вариант использования — простой выпадающий список для выбора значений: 

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")

option = st.selectbox(
    'Which Club do you like best?',
     df['Club'].unique())

'You selected: ', option
Простое приложение с виджетом dropdown/selectbox

5. Множественное выделение

Можно использовать несколько значений из выпадающего списка. Здесь мы используем st.multiselect, чтобы получить несколько значений списком в переменной options:

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")

options = st.multiselect(
 'What are your favorite clubs?', df['Club'].unique())

st.write('You selected:', options)
Простое приложение с виджетом multiselect

Создаем простое приложение 

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

Сначала попробуем визуализировать наши футбольные данные: с помощью уже знакомых нам виджетов сделать это не составит труда. 

import streamlit as st
import pandas as pd
import numpy as np

df = pd.read_csv("football_data.csv")

clubs = st.multiselect('Show Player for clubs?', df['Club'].unique())

nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique())

# Фильтрует данные 
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]

# выводит данные на экран
st.write(new_df)

Наше приложение выглядит так: 

Использование сочетания нескольких виджетов 

Это было просто. Но и выглядит несколько по-простецки. Может, добавить диаграммы? 

В настоящее время Streamlit поддерживает множество библиотек для отображения графических данных. Вот некоторые из них: Plotly, Bokeh, Matplotlib, Altair, and Vega charts. Plotly Express тоже работает, хоть в документации его и нет. Он также содержит встроенные типы диаграмм, нативные для Streamlit, например st.line_chart и st.area_chart.

Мы будем работать с plotly_express. Используем четыре вызова streamlit, все остальное просто код на python:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

df = pd.read_csv("football_data.csv")

clubs = st.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique())
new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)

# Создаем график, используя plotly express
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')

# Диаграмма!
st.plotly_chart(fig)
Добавление диаграмм

Улучшения

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

1. Кэширование

В нашем простом приложении мы перечитываем данные снова и снова при изменении значения. Это работает с малым объемом данных и не работает с большими данными или при необходимости много обрабатывать данные. Давайте используем кэширование с помощью функции-декоратора st.cache:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

df = st.cache(pd.read_csv)("football_data.csv")

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

@st.cache
def complex_func(a,b):
    DO SOMETHING COMPLEX

# Не запускается снова и снова. 
complex_func(a,b)

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

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

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

2. Боковая панель

Для более аккуратного вида в зависимости от ваших предпочтений можно перенести виджеты в боковую панель, что-то вроде дашборда Rshiny. Это очень просто — добавляем st.sidebar в код виджета. 

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

df = st.cache(pd.read_csv)("football_data.csv")

clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique())

new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)

# Создает distplot с пользовательским bin_size
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')

# Диаграмма!
st.plotly_chart(fig)
Перемещение виджета в боковую панель

3. Markdown?

Я люблю писать в Markdown. Как по мне, так он не такой многословный, как HTML, и больше подходит для работы с данными. Итак, можно ли использовать Markdown с приложением Streamlit?

Да, конечно. Существует несколько способов сделать это. Мне лучшим кажется использование магических команд. Они позволяют писать markdown так же просто, как комментарии. Можно использовать команду st.markdown:

import streamlit as st
import pandas as pd
import numpy as np
import plotly_express as px

'''
# Приложение Клуб и национальность. 

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

'''
df = st.cache(pd.read_csv)("football_data.csv")

clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique())
nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique())

new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))]
st.write(new_df)

# Создаем distplot с пользовательским bin_size
fig = px.scatter(new_df, x ='Overall',y='Age',color='Name')

'''
### Здесь простая диаграмма между возрастом игрока и остальными данными
'''st.plotly_chart(fig)
Итоговое демо приложения

Заключение

Streamlit демократизировал полный процесс создания приложений, и невозможно его не порекомендовать. 

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

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

Кроме того, Streamlit — это бесплатное приложение с открытым кодом, которое работает прямо из коробки. 

В прошлом мне приходилось обращаться к друзьям-разработчикам за любыми изменениями в демо или презентациях; теперь это стало относительно просто. 

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

Весь код рассмотренного приложения можно найти здесь.

Читайте также:


Перевод статьи Rahul Agarwal: How to write Web apps using simple Python for Data Scientists?