1. 项目简介

Streamlit是一个强大的Python库,用于快速构建和共享机器学习和数据科学Web应用。它的设计理念是让数据科学家和机器学习工程师能够以最小的代码量创建美观、交互式的Web应用,无需前端开发经验。

1.1 核心功能

  • 简单易用:使用Python脚本创建Web应用,无需HTML、CSS或JavaScript知识
  • 实时更新:代码修改后自动重新运行,提供即时反馈
  • 丰富的组件:提供各种UI组件,如滑块、按钮、表单等
  • 数据可视化:集成Matplotlib、Plotly等可视化库
  • 交互性:支持用户输入和实时响应

1.2 项目特点

  • 快速开发:几行代码即可创建功能完整的Web应用
  • 易于部署:支持多种部署方式,包括Streamlit Cloud、Heroku等
  • 开源免费:完全开源,可自由使用和修改
  • 活跃的社区:持续更新和改进
  • 适合原型开发:快速创建和分享数据科学原型

2. 安装与配置

2.1 安装Streamlit

# 安装Streamlit
pip install streamlit

# 验证安装
streamlit --version

# 运行示例应用
streamlit hello

2.2 安装依赖

# 安装常用数据科学库
pip install numpy pandas matplotlib seaborn plotly

# 安装机器学习库(可选)
pip install scikit-learn tensorflow pytorch

# 安装其他常用库(可选)
pip install pillow  # 图像处理
pip install requests  # HTTP请求

3. 核心概念

3.1 基本结构

Streamlit应用的基本结构非常简单,就是一个Python脚本,使用Streamlit的API创建UI组件和展示内容。

3.2 运行方式

  • 本地运行:使用streamlit run app.py命令运行
  • 部署:部署到Streamlit Cloud、Heroku等平台

3.3 主要API

  • **st.title()**:设置应用标题
  • **st.write()**:写入文本、数据框等内容
  • st.sidebar:创建侧边栏
  • **st.slider()**:创建滑块组件
  • **st.button()**:创建按钮
  • **st.selectbox()**:创建下拉选择框
  • **st.checkbox()**:创建复选框
  • **st.radio()**:创建单选按钮
  • **st.file_uploader()**:上传文件
  • **st.image()**:显示图像
  • **st.pyplot()**:显示Matplotlib图表
  • **st.plotly_chart()**:显示Plotly图表
  • **st.dataframe()**:显示数据框
  • **st.map()**:显示地图

3.4 状态管理

Streamlit使用会话状态(Session State)来管理应用的状态,允许在不同的用户交互之间保存数据。

4. 基本用法

4.1 创建简单应用

import streamlit as st

# 设置标题
st.title('我的第一个Streamlit应用')

# 写入文本
st.write('Hello, Streamlit!')

# 创建滑块
age = st.slider('请选择你的年龄', 0, 100, 25)

# 显示滑块值
st.write(f'你的年龄是: {age}')

# 创建按钮
if st.button('点击我'):
    st.write('你点击了按钮!')

# 创建复选框
if st.checkbox('显示隐藏内容'):
    st.write('这是隐藏的内容')

# 创建下拉选择框
option = st.selectbox(
    '你喜欢的编程语言',
    ['Python', 'Java', 'C++', 'JavaScript']
)

st.write(f'你选择了: {option}')

4.2 使用侧边栏

import streamlit as st

# 设置标题
st.title('使用侧边栏的应用')

# 创建侧边栏
st.sidebar.title('侧边栏')

# 在侧边栏添加组件
age = st.sidebar.slider('请选择你的年龄', 0, 100, 25)
option = st.sidebar.selectbox(
    '你喜欢的编程语言',
    ['Python', 'Java', 'C++', 'JavaScript']
)

# 显示侧边栏选择的值
st.write(f'你的年龄是: {age}')
st.write(f'你选择了: {option}')

4.3 数据可视化

import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import plotly.express as px

# 设置标题
st.title('数据可视化示例')

# 创建数据
np.random.seed(42)
data = np.random.normal(0, 1, 1000)

# 使用Matplotlib创建直方图
fig, ax = plt.subplots()
ax.hist(data, bins=30)
ax.set_title('正态分布直方图')
ax.set_xlabel('值')
ax.set_ylabel('频率')

# 显示Matplotlib图表
st.pyplot(fig)

# 使用Plotly创建散点图
df = pd.DataFrame({
    'x': np.random.randn(1000),
    'y': np.random.randn(1000),
    'size': np.random.randn(1000) * 100
})

fig = px.scatter(df, x='x', y='y', size='size', color='size', hover_name='x', size_max=60)
st.plotly_chart(fig)

# 显示数据框
df = pd.DataFrame(
    np.random.randn(10, 5),
    columns=['a', 'b', 'c', 'd', 'e']
)
st.dataframe(df)

4.4 文件上传和处理

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

# 设置标题
st.title('文件上传示例')

# 创建文件上传器
uploaded_file = st.file_uploader("选择一个CSV文件", type="csv")

if uploaded_file is not None:
    # 读取CSV文件
    df = pd.read_csv(uploaded_file)
    
    # 显示数据
    st.write('上传的数据:')
    st.dataframe(df)
    
    # 显示数据统计信息
    st.write('数据统计信息:')
    st.write(df.describe())

# 上传图像
st.title('图像上传示例')
uploaded_image = st.file_uploader("选择一个图像文件", type=["jpg", "jpeg", "png"])

if uploaded_image is not None:
    # 显示图像
    st.image(uploaded_image, caption='上传的图像')

5. 高级特性

5.1 会话状态

import streamlit as st

# 设置标题
st.title('会话状态示例')

# 初始化会话状态
if 'count' not in st.session_state:
    st.session_state.count = 0

# 增加计数的函数
def increment_counter():
    st.session_state.count += 1

# 减少计数的函数
def decrement_counter():
    st.session_state.count -= 1

# 创建按钮
col1, col2 = st.columns(2)

with col1:
    st.button('增加', on_click=increment_counter)

with col2:
    st.button('减少', on_click=decrement_counter)

# 显示计数
st.write(f'当前计数: {st.session_state.count}')

5.2 缓存

import streamlit as st
import time
import numpy as np

# 设置标题
st.title('缓存示例')

# 使用缓存装饰器
@st.cache_data
def expensive_computation(n):
    st.write(f'执行昂贵的计算,n={n}')
    time.sleep(2)  # 模拟耗时操作
    return np.random.randn(n)

# 创建滑块
n = st.slider('选择n的值', 1000, 10000, 5000)

# 调用缓存函数
data = expensive_computation(n)

# 显示结果
st.write(f'计算结果的均值: {data.mean()}')
st.write(f'计算结果的标准差: {data.std()}')

5.3 多页面应用

# 主应用文件 (app.py)
import streamlit as st
from pages import home, data, visualization

# 设置标题
st.sidebar.title('导航')

# 创建导航选择
page = st.sidebar.selectbox(
    '选择页面',
    ['首页', '数据', '可视化']
)

# 根据选择显示不同页面
if page == '首页':
    home.show()
elif page == '数据':
    data.show()
elif page == '可视化':
    visualization.show()

# pages/home.py
import streamlit as st

def show():
    st.title('首页')
    st.write('欢迎来到多页面应用!')

# pages/data.py
import streamlit as st
import pandas as pd
import numpy as np

def show():
    st.title('数据页面')
    df = pd.DataFrame(
        np.random.randn(10, 5),
        columns=['a', 'b', 'c', 'd', 'e']
    )
    st.dataframe(df)

# pages/visualization.py
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt

def show():
    st.title('可视化页面')
    data = np.random.normal(0, 1, 1000)
    fig, ax = plt.subplots()
    ax.hist(data, bins=30)
    st.pyplot(fig)

5.4 自定义主题

import streamlit as st

# 设置页面配置,包括主题
st.set_page_config(
    page_title="自定义主题示例",
    page_icon="🔍",
    layout="wide",
    initial_sidebar_state="expanded",
    menu_items={
        'Get Help': 'https://docs.streamlit.io/',
        'Report a bug': "https://github.com/streamlit/streamlit/issues",
        'About': "# 自定义主题示例应用"
    }
)

# 设置标题
st.title('自定义主题示例')

# 显示内容
st.write('这是一个使用自定义主题的Streamlit应用')

# 创建各种组件
st.slider('滑块示例', 0, 100, 50)
st.button('按钮示例')
st.selectbox('选择框示例', ['选项1', '选项2', '选项3'])

6. 实际应用案例

6.1 机器学习模型演示

场景:创建一个Web应用,演示机器学习模型的预测过程

步骤

  1. 加载预训练模型
  2. 创建用户输入界面
  3. 处理用户输入
  4. 显示模型预测结果

代码示例

import streamlit as st
import numpy as np
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier

# 加载数据和训练模型
iris = load_iris()
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(iris.data, iris.target)

# 设置标题
st.title('鸢尾花分类模型演示')

# 创建用户输入
st.sidebar.title('输入特征')
sepal_length = st.sidebar.slider('花萼长度 (cm)', 4.0, 8.0, 5.0)
sepal_width = st.sidebar.slider('花萼宽度 (cm)', 2.0, 4.5, 3.0)
petal_length = st.sidebar.slider('花瓣长度 (cm)', 1.0, 7.0, 4.0)
petal_width = st.sidebar.slider('花瓣宽度 (cm)', 0.1, 2.5, 1.0)

# 准备输入数据
input_data = np.array([[sepal_length, sepal_width, petal_length, petal_width]])

# 预测
prediction = model.predict(input_data)[0]
prediction_proba = model.predict_proba(input_data)[0]

# 显示结果
st.write('## 预测结果')
st.write(f'预测类别: {iris.target_names[prediction]}')
st.write('## 预测概率')
for i, class_name in enumerate(iris.target_names):
    st.write(f'{class_name}: {prediction_proba[i]:.4f}')

# 显示特征重要性
st.write('## 特征重要性')
feature_importance = model.feature_importances_
for i, feature in enumerate(iris.feature_names):
    st.write(f'{feature}: {feature_importance[i]:.4f}')

6.2 数据探索工具

场景:创建一个数据探索工具,允许用户上传数据并进行可视化分析

步骤

  1. 上传数据文件
  2. 显示数据概览
  3. 选择要分析的列
  4. 生成各种可视化图表

代码示例

import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px

# 设置标题
st.title('数据探索工具')

# 上传文件
uploaded_file = st.file_uploader("选择一个CSV文件", type="csv")

if uploaded_file is not None:
    # 读取数据
    df = pd.read_csv(uploaded_file)
    
    # 显示数据概览
    st.write('## 数据概览')
    st.write(f'数据形状: {df.shape}')
    st.write('前5行数据:')
    st.dataframe(df.head())
    
    # 显示数据类型
    st.write('## 数据类型')
    st.write(df.dtypes)
    
    # 显示缺失值
    st.write('## 缺失值')
    st.write(df.isnull().sum())
    
    # 选择要分析的列
    st.write('## 列选择')
    selected_columns = st.multiselect('选择要分析的列', df.columns.tolist())
    
    if selected_columns:
        # 显示选定列的统计信息
        st.write('## 统计信息')
        st.write(df[selected_columns].describe())
        
        # 选择图表类型
        chart_type = st.selectbox('选择图表类型', ['直方图', '散点图', '箱线图', '相关性热图'])
        
        if chart_type == '直方图':
            # 选择要绘制直方图的列
            hist_column = st.selectbox('选择列', selected_columns)
            fig, ax = plt.subplots()
            ax.hist(df[hist_column].dropna(), bins=30)
            ax.set_title(f'{hist_column}的直方图')
            st.pyplot(fig)
            
        elif chart_type == '散点图':
            # 选择X和Y轴
            x_column = st.selectbox('选择X轴', selected_columns)
            y_column = st.selectbox('选择Y轴', selected_columns)
            fig = px.scatter(df, x=x_column, y=y_column)
            st.plotly_chart(fig)
            
        elif chart_type == '箱线图':
            # 选择要绘制箱线图的列
            box_column = st.selectbox('选择列', selected_columns)
            fig, ax = plt.subplots()
            ax.boxplot(df[box_column].dropna())
            ax.set_title(f'{box_column}的箱线图')
            st.pyplot(fig)
            
        elif chart_type == '相关性热图':
            # 计算相关性
            corr = df[selected_columns].corr()
            fig, ax = plt.subplots(figsize=(10, 8))
            sns.heatmap(corr, annot=True, cmap='coolwarm', ax=ax)
            ax.set_title('相关性热图')
            st.pyplot(fig)

6.3 实时数据监控仪表板

场景:创建一个实时数据监控仪表板,显示模拟的传感器数据

步骤

  1. 生成模拟数据
  2. 创建实时更新的图表
  3. 显示关键指标
  4. 添加警报功能

代码示例

import streamlit as st
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import time

# 设置页面配置
st.set_page_config(page_title="实时数据监控", layout="wide")

# 设置标题
st.title('实时数据监控仪表板')

# 初始化数据
if 'data' not in st.session_state:
    st.session_state.data = pd.DataFrame(
        {
            '时间': pd.date_range(start=pd.Timestamp.now(), periods=10, freq='s'),
            '温度': np.random.normal(25, 2, 10),
            '湿度': np.random.normal(60, 5, 10),
            '压力': np.random.normal(1013, 5, 10)
        }
    )

# 创建布局
col1, col2, col3 = st.columns(3)

with col1:
    st.metric('当前温度', f"{st.session_state.data['温度'].iloc[-1]:.2f} °C")

with col2:
    st.metric('当前湿度', f"{st.session_state.data['湿度'].iloc[-1]:.2f} %")

with col3:
    st.metric('当前压力', f"{st.session_state.data['压力'].iloc[-1]:.2f} hPa")

# 创建图表
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 8))

# 绘制温度
ax1.plot(st.session_state.data['时间'], st.session_state.data['温度'], 'r-')
ax1.set_title('温度变化')
ax1.set_ylabel('温度 (°C)')

# 绘制湿度
ax2.plot(st.session_state.data['时间'], st.session_state.data['湿度'], 'g-')
ax2.set_title('湿度变化')
ax2.set_ylabel('湿度 (%)')

# 绘制压力
ax3.plot(st.session_state.data['时间'], st.session_state.data['压力'], 'b-')
ax3.set_title('压力变化')
ax3.set_ylabel('压力 (hPa)')
ax3.set_xlabel('时间')

plt.tight_layout()
st.pyplot(fig)

# 模拟数据更新
if st.button('开始实时更新'):
    placeholder = st.empty()
    
    for _ in range(50):
        # 生成新数据
        new_data = pd.DataFrame(
            {
                '时间': [pd.Timestamp.now()],
                '温度': [np.random.normal(25, 2)],
                '湿度': [np.random.normal(60, 5)],
                '压力': [np.random.normal(1013, 5)]
            }
        )
        
        # 更新数据
        st.session_state.data = pd.concat([st.session_state.data, new_data]).tail(50)
        
        # 更新布局
        with placeholder.container():
            col1, col2, col3 = st.columns(3)
            
            with col1:
                st.metric('当前温度', f"{st.session_state.data['温度'].iloc[-1]:.2f} °C")
            
            with col2:
                st.metric('当前湿度', f"{st.session_state.data['湿度'].iloc[-1]:.2f} %")
            
            with col3:
                st.metric('当前压力', f"{st.session_state.data['压力'].iloc[-1]:.2f} hPa")
            
            # 更新图表
            fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 8))
            
            # 绘制温度
            ax1.plot(st.session_state.data['时间'], st.session_state.data['温度'], 'r-')
            ax1.set_title('温度变化')
            ax1.set_ylabel('温度 (°C)')
            
            # 绘制湿度
            ax2.plot(st.session_state.data['时间'], st.session_state.data['湿度'], 'g-')
            ax2.set_title('湿度变化')
            ax2.set_ylabel('湿度 (%)')
            
            # 绘制压力
            ax3.plot(st.session_state.data['时间'], st.session_state.data['压力'], 'b-')
            ax3.set_title('压力变化')
            ax3.set_ylabel('压力 (hPa)')
            ax3.set_xlabel('时间')
            
            plt.tight_layout()
            st.pyplot(fig)
        
        # 检查警报
        if st.session_state.data['温度'].iloc[-1] > 30:
            st.error('温度过高!')
        if st.session_state.data['湿度'].iloc[-1] > 80:
            st.error('湿度过高!')
        if st.session_state.data['压力'].iloc[-1] < 1000:
            st.error('压力过低!')
        
        # 等待一秒
        time.sleep(1)

7. 总结与展望

Streamlit为数据科学家和机器学习工程师提供了一种快速构建和共享Web应用的方法,无需前端开发经验。它的简单易用、实时更新和丰富的组件使其成为数据科学原型开发和可视化的理想工具。

7.1 主要优势

  • 简单易用:使用Python脚本创建Web应用,无需HTML、CSS或JavaScript知识
  • 快速开发:几行代码即可创建功能完整的Web应用
  • 实时更新:代码修改后自动重新运行,提供即时反馈
  • 丰富的组件:提供各种UI组件,如滑块、按钮、表单等
  • 数据可视化:集成Matplotlib、Plotly等可视化库
  • 易于部署:支持多种部署方式,包括Streamlit Cloud、Heroku等

7.2 未来发展

  • 更多组件:持续添加新的UI组件和功能
  • 更好的性能:优化大型应用的性能
  • 更丰富的集成:与更多数据科学库和工具集成
  • 更好的文档:提供更详细的文档和示例
  • 更广泛的应用场景:拓展到更多领域和行业

Streamlit正在改变数据科学和机器学习的工作方式,通过掌握Streamlit,数据科学家可以更快速地创建和分享他们的工作,加速AI应用的开发和落地。