Streamlit для аналитика: data apps за час

Зачем аналитику Streamlit

У аналитика регулярно возникает ситуация: есть Python-скрипт с интересным анализом, но показать его бизнесу — проблема. Jupyter notebook менеджер не откроет, dashboard в Tableau долго делать, frontend-разработчик занят.

Streamlit решает эту задачу. За час вы превращаете Python-скрипт в интерактивное web-приложение, которое можно открыть в браузере и показать команде. Без HTML, CSS, JavaScript. Только Python.

Типовые use-cases: интерактивный calculator ROI, дашборд с фильтрами для специфической задачи, демо ML-модели для PM, sharing аналитических insights вне Tableau/Metabase.

Минимальный пример

Установка:

pip install streamlit

Скрипт app.py:

import streamlit as st
import pandas as pd

st.title('Анализ продаж')

# Загружаем данные
df = pd.read_csv('sales.csv')

st.write(f'Всего записей: {len(df)}')
st.dataframe(df.head(10))

# График
st.bar_chart(df.groupby('category')['amount'].sum())

Запуск:

streamlit run app.py

Открывается браузер с локальным приложением. Три строки кода — interactive app с таблицей и графиком.

Виджеты для интерактивности

Главная ценность Streamlit — простые виджеты для взаимодействия:

import streamlit as st
import pandas as pd

df = pd.read_csv('sales.csv')

# Выбор категории
category = st.selectbox('Категория', df['category'].unique())

# Диапазон дат
date_range = st.date_input('Период', [df['date'].min(), df['date'].max()])

# Чекбокс
show_refunded = st.checkbox('Включить возвраты', value=False)

# Слайдер
min_amount = st.slider('Минимальная сумма', 0, 10000, 100)

# Фильтрация
filtered = df[
    (df['category'] == category) &
    (df['date'] >= date_range[0]) & (df['date'] <= date_range[1]) &
    (df['amount'] >= min_amount)
]
if not show_refunded:
    filtered = filtered[filtered['status'] != 'refunded']

st.write(f'Найдено {len(filtered)} записей на {filtered["amount"].sum():,.0f} руб')
st.dataframe(filtered)

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

Графики

Streamlit умеет рендерить plotly, matplotlib, seaborn, altair:

import plotly.express as px

fig = px.line(daily_data, x='date', y='revenue', color='region')
st.plotly_chart(fig)

Для простых случаев — встроенные команды:

st.line_chart(df[['revenue']])
st.bar_chart(df.groupby('day')['orders'].sum())
st.area_chart(df[['new_users', 'returning_users']])

Этого хватает для 80% дашбордов.

Layout

Виджеты можно располагать в колонках и вкладках:

col1, col2, col3 = st.columns(3)

col1.metric('Revenue', '₽1.2M', '+12%')
col2.metric('Orders', '4,567', '+8%')
col3.metric('AOV', '₽263', '-3%')

tab1, tab2, tab3 = st.tabs(['Overview', 'Sales', 'Customers'])

with tab1:
    st.write('Обзор бизнеса')
    st.line_chart(...)

with tab2:
    st.write('Детали продаж')
    st.bar_chart(...)

with tab3:
    st.write('Клиенты')
    st.dataframe(...)

Это даёт профессионально выглядящий дашборд без HTML.

Кэширование

Для медленных операций (тяжёлые SQL, скачивание файлов) — декоратор @st.cache_data:

@st.cache_data
def load_orders():
    # Эта функция запустится один раз
    return pd.read_sql('SELECT * FROM orders', engine)

df = load_orders()  # При повторных запусках скрипта — из кэша

Без кэша скрипт при каждом клике перечитывал бы SQL. С кэшем — только один раз за сессию.

@st.cache_resource — для non-data объектов (соединения с БД, ML-модели):

@st.cache_resource
def load_model():
    return joblib.load('model.pkl')

model = load_model()

Пример: RFM-дашборд

Реальное применение — интерактивный RFM:

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

st.set_page_config(page_title='RFM', layout='wide')

st.title('RFM Analysis')

# Загрузка
@st.cache_data
def load_data():
    return pd.read_sql("""
        SELECT user_id, created_at, amount FROM orders WHERE status = 'paid'
    """, conn)

df = load_data()

# Фильтры в сайдбаре
min_date = st.sidebar.date_input('С даты', df['created_at'].min())
max_date = st.sidebar.date_input('По дату', df['created_at'].max())

df_filtered = df[(df['created_at'] >= min_date) & (df['created_at'] <= max_date)]

# Расчёт RFM
rfm = df_filtered.groupby('user_id').agg(
    recency=('created_at', lambda x: (pd.Timestamp.now() - x.max()).days),
    frequency=('user_id', 'count'),
    monetary=('amount', 'sum')
).reset_index()

# Quantiles
rfm['R_score'] = pd.qcut(rfm['recency'], 5, labels=[5,4,3,2,1])
rfm['F_score'] = pd.qcut(rfm['frequency'], 5, labels=[1,2,3,4,5])
rfm['M_score'] = pd.qcut(rfm['monetary'], 5, labels=[1,2,3,4,5])
rfm['RFM'] = rfm['R_score'].astype(str) + rfm['F_score'].astype(str) + rfm['M_score'].astype(str)

# Визуализация
col1, col2 = st.columns(2)

with col1:
    st.metric('Total customers', len(rfm))
    st.metric('Avg monetary', f'{rfm["monetary"].mean():,.0f}')

with col2:
    fig = px.scatter(rfm, x='frequency', y='monetary', color='R_score',
                     title='Frequency vs Monetary')
    st.plotly_chart(fig)

# Сегменты
st.subheader('Топ-10 VIP')
st.dataframe(rfm.nlargest(10, 'monetary'))

Час работы — полноценный interactive dashboard. Бизнес может крутить фильтры, смотреть данные, находить insights.

Разбираться с быстрыми инструментами для прототипирования — полезная часть senior-работы. В тренажёре Карьерник есть Python-задачи для аналитика, включая работу с инструментами data-сообщества.

Deployment

Локально streamlit запускается через streamlit run app.py. Для sharing с командой — несколько вариантов:

Streamlit Community Cloud — бесплатный хостинг, нужен git-репозиторий. Деплой за минуту, public URL.

Hugging Face Spaces — бесплатно для public приложений, хорошая интеграция с ML-моделями.

Собственный сервер — Docker-контейнер, nginx впереди. Для корпоративного использования.

Streamlit Snowflake — если вы на Snowflake, есть встроенный deployment внутри их платформы.

Аутентификация

По умолчанию Streamlit-apps открыты всем, кто знает URL. Для корпоративного использования нужна защита.

Варианты:

  • Streamlit-authenticator — Python-пакет для login/password.
  • OAuth через Google/GitHub — через внешние middleware.
  • Reverse proxy с basic auth — на уровне инфраструктуры.
  • Streamlit Cloud Team — встроенная SSO в платной версии.

Для внутренних демо обычно хватает первых двух.

Когда Streamlit подходит

Идеален для:

Быстрых internal tools — калькуляторы, дашборды для отдельной команды.

Демо ML-моделей — загрузить модель, показать predictions в UI.

Ad-hoc аналитических приложений — когда разовая задача заслуживает интерактивности.

Прототипов — проверить идею UI до того, как отдать frontend-команде.

Когда Streamlit НЕ подходит

Production-приложения с тысячами пользователей. Streamlit однопоточный по natureй, для масштаба нужны Django/FastAPI + React.

Сложные UI с кастомным дизайном. Streamlit — opinionated, стили ограничены.

Приложения с реальным real-time (websocket, chat). Streamlit обновляется по запросу, не streaming.

Mobile-first приложения. Работает на мобильных, но experience не идеальный.

Альтернативы

Gradio — похоже на Streamlit, но больше фокус на ML. Хорошо для модельных демо.

Dash (by Plotly) — больше контроля, сложнее, ближе к fullstack. Для production дашбордов.

Panel — мощнее Streamlit, но learning curve выше.

Voilà — превращает Jupyter notebook в app. Простейший способ, но ограниченный.

Для аналитика самый быстрый вход — Streamlit. Остальное — когда нужно больше.

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

FAQ

Сколько учить?

Базовый уровень — 1-2 дня. Уверенное владение — неделя.

Что быстрее — Streamlit или Tableau?

Streamlit быстрее для прототипов и custom-логики. Tableau быстрее для типовых BI-дашбордов с drag-n-drop.

Можно ли связать с БД?

Да, любым Python-способом: SQLAlchemy, psycopg2, clickhouse-driver. @st.cache_data для кэширования.

Streamlit бесплатный?

Да, open-source. Streamlit Community Cloud для деплоя тоже бесплатный. Платная версия Snowflake Streamlit — только если вы на Snowflake.