Python 实战笔记:从 Pandas 描述性统计、SciPy 假设检验到 FastAPI 服务端开发
前言
在数据科学的实际工作中,我们经常需要在“统计分析”和“应用开发”两种思维模式间切换。今天的实战笔记将通过具体且独立的业务场景,串联起 Python 数据生态中的三个核心库:Pandas(用于数据概览)、SciPy(用于假设验证)和 FastAPI(用于服务部署)。
下面通过三个独立案例,记录代码涉及的统计思路和 Python API。
第一部分:Pandas 中的描述性统计 (Descriptive Statistics)
处理矩阵数据(DataFrame)时,需要先分清统计操作按行还是按列执行。这里用股票市场数据或多店铺销售数据举例。
1. 核心知识点
-
均值 (Mean): 数据的中心趋势。
-
标准差 (Standard Deviation, SD): 反映数据的波动性(风险)。
-
标准误差 (Standard Error of the Mean, SEM): 反映样本均值的估算精确度。
-
区别点:SD 衡量数据本身的离散度(例如股票每天涨跌多剧烈),SEM 衡量均值的可靠性。
-
轴 (Axis) 的概念:
axis=0: 跨行操作(沿着纵向切),通常用于计算某一特征(列)在不同样本间的表现。axis=1: 跨列操作(沿着横向切),通常用于计算某一样本(行)在不同维度下的综合表现。
2. 实战案例:多店铺销售分析
假设我们有一个 DataFrame,每一行代表一天,每一列代表一个分店的销售额。
import pandas as pd
def analyze_sales_metrics(df): """ 输入: df (Pandas DataFrame) - 包含多店销售数据 输出: daily_average: 每一天的全店平均销量 (基于行) daily_volatility: 每一天的销量波动 (基于行) store_average: 每个店铺的平均销量 (基于列) store_reliability: 每个店铺销量均值的标准误 (基于列) """ # 1. 计算单日全店平均业绩 (Row Mean) # axis=1: 横向计算,聚合所有店铺当天的数据 daily_average = df.mean(axis=1)
# 2. 计算单日业绩差异 (Row Standard Deviation) # 如果标准差大,说明当天有的店卖得好,有的卖得差 # Pandas 默认 ddof=1 (样本标准差) daily_volatility = df.std(axis=1)
# 3. 计算店铺长期平均表现 (Column Sample Mean) # axis=0: 纵向计算,算出该列(该店铺)的历史平均值 store_average = df.mean(axis=0)
# 4. 计算店铺表现的稳定性 (Column Sample Error) # 使用 sem() 函数直接计算标准误差 store_reliability = df.sem(axis=0)
return daily_average, daily_volatility, store_average, store_reliability第二部分:SciPy 中的假设检验 (Hypothesis Testing)
统计检验用于判断观测到的现象是否具有显著性。
1. 卡方检验 (Chi-square Test) —— 网站流量来源是否异常?
场景: 假设我们要验证某网站在一周 7 天内的访问量分布是否均匀,或者是否符合特定的预期比例(例如周末流量通常更高)。
核心逻辑:
- 观测频数 (Observed): 实际统计到的每天访问人数。
- 期望频数 (Expected): 按照理论模型(如均匀分布)计算出的预期人数。
代码解析:
from scipy.stats import chisquare
def check_traffic_distribution(daily_visitors): """ 输入: daily_visitors (list) - 一周7天的实际访问量列表 """ total_traffic = sum(daily_visitors) days_count = len(daily_visitors) # 应当为 7
# 1. 设定“尺子”:假设流量应该是均匀分布的 # 理论概率 = 1/7 expected_prob = 1.0 / days_count
# 2. 计算期望频数 (Expected Frequencies) # 如果完全均匀,每天应该有多少人 f_exp = [total_traffic * expected_prob] * days_count
# 3. 观测频数即为输入数据 f_obs = daily_visitors
# 4. 执行卡方检验 # 对比“实际分布”和“均匀分布”的差异 result = chisquare(f_obs=f_obs, f_exp=f_exp)
# 如果 p_value < 0.05,说明流量分布显著不均匀 return result.pvalue, result.statistic2. 配对检验 —— 算法优化前后的效果对比
场景: 我们对同一组服务器进行了系统升级,想要对比升级前(Column A)和升级后(Column B)的响应时间。由于是同一组服务器的前后对比,这属于配对数据。
代码解析:
from scipy.stats import ttest_rel, wilcoxon
def compare_system_performance(df): """ 假设 df 第一列是 Upgrade_Before,第二列是 Upgrade_After """ response_time_before = df.iloc[:, 0] response_time_after = df.iloc[:, 1]
# 方法1: 配对 T 检验 (Paired T-test) # 适用条件:假设响应时间的差值服从正态分布 p_ttest = ttest_rel(response_time_before, response_time_after).pvalue
# 方法2: Wilcoxon 符号秩检验 # 适用条件:不确定分布形态,或存在离群点(非参数检验) # 它通过比较“排名”而非具体数值来判断差异 p_wilcoxon = wilcoxon(response_time_before, response_time_after).pvalue
return p_ttest, p_wilcoxon第三部分:FastAPI 服务端开发 (Web Implementation)
做完模型或逻辑验证后,我们常需要将其封装为微服务。这里演示如何使用 FastAPI 构建一个商品折扣计算器(Discount Calculator)。
1. 核心知识点
- Pydantic (
BaseModel): 定义数据契约。确保传入的价格和折扣率都是合法的数字。 - 表单处理 (
Form): 处理传统的 HTML 表单提交。 - 模板渲染 (
Jinja2Templates): 实现前后端分离的简单页面展示。
2. 代码实战:商品折扣计算 API
这是一个完整的后端服务脚本。
# 引入必要的库from typing import Annotatedfrom fastapi import FastAPI, Form, Requestfrom fastapi.responses import JSONResponse, HTMLResponsefrom fastapi.encoders import jsonable_encoderfrom fastapi.templating import Jinja2Templatesfrom pydantic import BaseModelimport uvicorn
# --- 知识点 1: 定义数据模型 ---# 规定前端提交的数据结构class ProductInfo(BaseModel): original_price: float discount_rate: float # 例如 0.9 代表 9折
app = FastAPI()# 设置存放 HTML 文件的文件夹 (需手动创建 templates 目录)templates = Jinja2Templates(directory='templates')
# --- 知识点 2: 编写 API 接口 ---
# 接口 A: 计算折后价格 (POST 请求)# 当用户在网页表单点击“计算”时触发@app.post("/calculate_discount/")async def calculate(data: Annotated[ProductInfo, Form()]): price = data.original_price rate = data.discount_rate
# 简单的业务逻辑校验 if price < 0 or rate < 0: response_data = {"final_price": 0, "message": "Price or rate cannot be negative."} else: final_price = price * rate response_data = { "final_price": round(final_price, 2), "message": "Success" }
# 返回 JSON 格式的数据 return JSONResponse(content=jsonable_encoder(response_data), status_code=200)
# 接口 B: 渲染前端页面 (GET 请求)# 访问根路径时显示计算器页面@app.get('/', response_class=HTMLResponse)async def home(request: Request): # 返回 calculator.html 页面 # 确保 templates/calculator.html 存在 return templates.TemplateResponse('calculator.html', {'request': request})
# --- 知识点 3: 启动服务器 ---if __name__ == "__main__": # 启动命令:python main.py # 访问地址:http://localhost:8000 uvicorn.run(app, host="0.0.0.0", port=8000)总结
通过这三个独立案例,我们完成了一次技术闭环:
- 利用 Pandas 对业务数据进行多维度的描述统计。
- 利用 SciPy 科学地验证数据变化的显著性。
- 利用 FastAPI 将核心计算逻辑快速转化为可交互的 Web 服务。
建议在本地环境复现上述代码,并尝试修改其中的业务逻辑(例如将折扣计算改为房贷计算),以加深对框架的理解。
