数据看得见,决策才更快
数据仪表盘(Dashboard)是数据分析师最重要的交付物——将复杂数据浓缩为一屏可视化的关键指标和图表,让决策者一眼看懂业务状况。
| 框架 | 语言 | 优点 | 缺点 | 适合 |
|---|---|---|---|---|
| Streamlit | Python | 极速开发 | 定制性弱 | 原型/内部 |
| Dash | Python | 灵活定制 | 学习曲线陡 | 企业级 |
| Gradio | Python | ML Demo | 非仪表盘 | 模型展示 |
| Shiny | R/Python | 统计友好 | R生态 | 统计分析 |
| Superset | SQL | 开箱即用 | 定制弱 | BI报表 |
| Metabase | SQL | 最简单 | 复杂分析弱 | 业务自助 |
Streamlit是2024年最火的Python数据应用框架,无需前端知识,纯Python写仪表盘。
# app.py — 电商数据分析仪表盘
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
# ===== 页面配置 =====
st.set_page_config(
page_title="电商数据分析仪表盘",
page_icon="📊",
layout="wide"
)
# ===== 数据加载(带缓存) =====
@st.cache_data
def load_data():
months = pd.date_range('2024-01', periods=12, freq='ME')
sales = [1200, 1350, 1480, 1620, 1550, 1780, 1950, 2100,
1880, 2250, 2480, 2800] # 万元
orders = [3200, 3500, 3800, 4100, 3900, 4500, 4800, 5200,
4700, 5600, 6100, 6900]
return pd.DataFrame({
'month': months.strftime('%Y-%m'),
'sales': sales,
'orders': orders,
})
df = load_data()
# ===== 侧边栏 =====
st.sidebar.header("🎯 筛选器")
selected_months = st.sidebar.multiselect(
"选择月份", df['month'].tolist(), default=df['month'].tolist()
)
df_filtered = df[df['month'].isin(selected_months)]
# ===== KPI卡片 =====
col1, col2, col3, col4 = st.columns(4)
col1.metric("总销售额", f"¥{df_filtered['sales'].sum()/10000:.2f}亿",
f"+{15.3:.1f}%")
col2.metric("总订单数", f"{df_filtered['orders'].sum():,}",
f"+{12.8:.1f}%")
col3.metric("客单价", f"¥{df_filtered['sales'].sum()*10000/df_filtered['orders'].sum():.0f}")
col4.metric("复购率", "91.7%", "+3.2%")
# ===== 图表区 =====
st.subheader("📈 月度销售趋势")
fig_trend = px.line(df_filtered, x='month', y='sales',
title='月度销售额(万元)',
markers=True)
fig_trend.update_traces(line_color='#3b82f6')
st.plotly_chart(fig_trend, use_container_width=True)
col1, col2 = st.columns(2)
with col1:
# 品类饼图
cat_data = pd.DataFrame({
'category': ['电子', '服装', '食品', '家居', '美妆', '图书'],
'sales_pct': [38.5, 22.3, 15.8, 11.2, 8.6, 3.6]
})
fig_pie = px.pie(cat_data, values='sales_pct', names='category',
title='品类销售占比')
st.plotly_chart(fig_pie)
with col2:
# 增长率柱状图
fig_bar = px.bar(cat_data, x='category', y='sales_pct',
title='品类销售占比(%)',
color='sales_pct', color_continuous_scale='Blues')
st.plotly_chart(fig_bar)
# ===== RFM分群 =====
st.subheader("👥 RFM用户分群")
rfm_data = pd.DataFrame({
'segment': ['重要价值', '重要发展', '重要保持', '一般价值', '一般发展', '流失预警'],
'users': [8500, 6200, 4100, 3800, 5200, 8900],
'sales_pct': [45.2, 28.3, 15.6, 6.8, 3.2, 0.9],
})
fig_rfm = px.treemap(rfm_data, path=['segment'], values='users',
color='sales_pct', color_continuous_scale='Blues',
title='RFM用户分群')
st.plotly_chart(fig_rfm, use_container_width=True)
streamlit run app.py,浏览器自动打开 http://localhost:8501Dash是Plotly出品的企业级仪表盘框架,基于React+Flask,适合需要精细控制UI的场景。
# dash_app.py — Dash电商仪表盘
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd
app = Dash(__name__)
# 布局定义
app.layout = html.Div(style={'backgroundColor': '#0f0f1a', 'color': '#e0e0e0', 'padding': '20px'}, children=[
html.H1("📊 电商数据分析仪表盘",
style={'color': '#3b82f6', 'marginBottom': '20px'}),
# 筛选器
html.Div([
html.Label("选择月份:"),
dcc.Dropdown(id='month-dropdown',
options=[{'label': m, 'value': m} for m in months_list],
value=months_list[0],
style={'color': '#000'})
], style={'width': '300px', 'marginBottom': '20px'}),
# KPI卡片
html.Div(id='kpi-cards', style={'display': 'flex', 'gap': '20px',
'marginBottom': '20px'}),
# 图表
dcc.Graph(id='sales-trend'),
html.Div([
dcc.Graph(id='category-pie', style={'width': '50%'}),
dcc.Graph(id='growth-bar', style={'width': '50%'})
], style={'display': 'flex'})
])
# 回调:筛选器→更新图表
@callback(
Output('sales-trend', 'figure'),
Input('month-dropdown', 'value')
)
def update_trend(selected_month):
fig = px.line(df, x='month', y='sales',
title=f'{selected_month} 销售趋势')
fig.update_layout(plot_bgcolor='#1a1a2e',
paper_bgcolor='#1a1a2e',
font_color='#e0e0e0')
return fig
if __name__ == '__main__':
app.run(debug=True)
| 对比 | Streamlit | Dash |
|---|---|---|
| 开发速度 | ⚡⚡⚡⚡⚡ (最快) | ⭐⭐⭐ |
| 定制性 | ⭐⭐⭐ | ⚡⚡⚡⚡⚡ (最灵活) |
| 学习曲线 | ⚡ (最简单) | ⭐⭐⭐ |
| 性能 | ⭐⭐⭐ | ⚡⚡⚡⚡ |
| 部署 | Streamlit Cloud | 任何WSGI服务器 |
| 适用规模 | 中小 | 任意 |
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
np.random.seed(42)
# ===== 数据准备 =====
months = pd.date_range('2024-01', periods=12, freq='ME')
sales = np.array([120, 135, 148, 162, 155, 178, 195, 210,
188, 225, 248, 280]) * 10000
orders = np.array([3200, 3500, 3800, 4100, 3900, 4500, 4800,
5200, 4700, 5600, 6100, 6900])
df = pd.DataFrame({'month': months.strftime('%Y-%m'),
'sales': sales, 'orders': orders})
# RFM分群
rfm = [("重要价值", 8500, 45.2), ("重要发展", 6200, 28.3),
("重要保持", 4100, 15.6), ("一般价值", 3800, 6.8),
("一般发展", 5200, 3.2), ("流失预警", 8900, 0.9)]
# 转化漏斗
funnel = [("曝光", 1000000), ("点击", 85000), ("加购", 32000),
("下单", 15000), ("支付", 12000)]
# 预测模型
X, y = make_classification(n_samples=1000, n_features=10, random_state=42)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_tr, y_tr)
print(f"模型准确率: {accuracy_score(y_te, rf.predict(X_te)):.4f}")
print(f"年度总销售额: ¥{df.sales.sum()/1e8:.2f}亿")
print(f"转化率: 支付/曝光 = {12000/1000000*100:.2f}%")