基于Flask的城市网约车行程分析与时长需求预测系统设计与实现 毕业论文
毕业设计
一、项目名称:
基于Flask的城市网约车行程分析与时长需求预测系统设计与实现
【摘要】
城市网约车行程具有显著的空间热点、行政区 OD 差异与时段高峰特征,仅靠表格浏览难以快速把握上车区域热度、跨区流向、行程时长分布、需求时序与费用支付结构。本文设计并实现基于 Flask 的城市网约车行程分析与时长需求预测系统,面向毕业设计与教学演示,将上车区域对照、行程明细统一入库后,以交互式图表完成多维可视化,并以随机森林完成小时需求或均时长的一键预测,辅以智谱大模型问答与自研后台维护。
系统采用 B/S 架构,后端入口为 app.py,运行端口 8082;数据库使用 MySQL(库名 ridehail),经 PyMySQL 访问。前台基于 Bootstrap、本地 static/vendor 中的 ECharts,配合 ride-theme.css 主题(主色琥珀 #c2410c),登录背景为 ride-bg.jpg。核心业务表包括 tbl_user、ride_zones、ride_trips(含 duration_min/trip_distance/pu_borough/total_amount/payment_name 等)。可视化聚合在 utils/ride_viz_charts.py 中按行政区、月份输出图表 bundle,并带短时缓存;随机森林预测由 models/random_forest_model.py 实现,页面路径 /ride/rf_predict;AI 助手类为 RideAIAssistant,调用智谱 OpenAI 兼容接口,默认模型 glm-4-flash。后台为自研 CRUD(utils/admin_blueprint.py),路径 /admin/,独立登录页 /admin/login,覆盖用户、上车区域、行程明细三类数据。默认账号 admin/admin123。主数据来自微软 T-Drive 北京出租车 GPS 轨迹,经 fetch_beijing_tdrive.py、process_tdrive_trips.py 切分后由 import_tlc_trips.py 导入,推荐规模约 15349 条行程、398 个区域;费用与支付方式按国内计价规则与常见结构衍生,详见 data/DATA_SOURCES.md。
测试与运行表明,系统可完成登录注册、首页 KPI 总览、六类行程可视化、数据总览、随机森林预测、AI 问答与后台维护等闭环,界面清晰、响应稳定,可为网约车行程分析课题研究与教学演示提供可用支撑。
【关键词】 Flask;网约车;行程分析;随机森林;ECharts
【Abstract】
Urban ride-hailing trips exhibit strong spatial hotspots, borough-level OD patterns and hourly demand peaks, making spreadsheet browsing inefficient. This thesis designs and implements a Flask-based ride-hailing trip analysis and duration/demand forecasting system for graduation design and teaching demos. Zone lookup and trip records are stored in MySQL and explored through interactive charts, with one-click Random Forest forecasting, Zhipu LLM Q&A and a custom admin backend.
The system follows a B/S architecture. The entry is app.py on port 8082. MySQL database name is ridehail, accessed via PyMySQL. The frontend uses Bootstrap, local ECharts under static/vendor, and ride-theme.css (amber #c2410c) with login background ride-bg.jpg. Core tables include tbl_user, ride_zones, and ride_trips. Visualization bundles are built in ride_viz_charts.py with short TTL cache. Random Forest forecasting is implemented in random_forest_model.py at /ride/rf_predict. The AI assistant class RideAIAssistant uses Zhipu’s OpenAI-compatible API with default model glm-4-flash. Admin CRUD is custom (admin_blueprint.py) at /admin/ with independent login /admin/login. Default account is admin/admin123. Primary data come from Microsoft T-Drive Beijing taxi GPS trajectories, yielding about 15,349 trips and 398 zones after recommended import.
Results show that authentication, home KPI overview, multi-dimensional trip visualization, data overview, Random Forest prediction, AI assistant and admin maintenance work stably for course demos.
【Keywords】 Flask; Ride-Hailing; Trip Analysis; Random Forest; ECharts
目 录
- 2.1 Python编程语言
- 2.2 Flask Web框架
- 2.3 MySQL与PyMySQL
- 2.4 pandas与scikit-learn随机森林
- 2.5 ECharts与ride-theme
- 2.6 智谱AI与技术特色
- 4.0 系统整体实现流程
- 4.1 用户认证模块的实现
- 4.2 行程多维可视化模块的实现
- 4.3 数据总览模块的实现
- 4.4 随机森林需求时长预测模块的实现
- 4.5 AI智能助手模块的实现
- 4.6 后台数据管理模块的实现
- 4.7 用户界面实现
- 4.8 系统集成与部署
1 绪 论
1.1 课题研究背景
网约车行程数据是城市出行调度、运力配置与交通治理的重要依据。上车热点、跨行政区 OD 流向、行程时长与距离、高峰需求时序、费用结构与支付方式等因素交织,使订单量在空间与时间维度上呈现显著差异。对教学与课题研究而言,若仅依赖表格逐行浏览,难以从区域热度、流向结构、时长分布、需求曲线与费用构成等维度形成整体认识。与此同时,毕业设计场景需要一套可本地部署、结构清晰、图表可读的系统,既要能装载可演示的真实轨迹切分行程,也要能给出可解释的短期预测结果。
本课题据此构建「基于Flask的城市网约车行程分析与时长需求预测系统设计与实现」:以 Flask 提供页面与 JSON 接口,以 MySQL 库 ridehail 持久化上车区域对照与行程明细,以 ECharts 完成多页可视化看板,以 scikit-learn 随机森林完成一站式训练与预测,并以智谱 glm-4-flash 提供行程分析问答。系统入口 app.py 监听 8082 端口;侧栏覆盖首页总览、六类行程可视化、数据总览、随机森林预测与 AI 助手;管理端为自研 /admin/ CRUD。主数据采用微软 T-Drive 北京出租车 GPS 公开轨迹(data/raw/tdrive/),经切分脚本生成约 15349 条行程样本;费用与支付字段按国内计价规则与常见支付方式衍生,区域对照约 398 条。该背景决定了后续技术选型必须兼顾轻量部署、图表交互与预测可演示性。
1.2 课题研究的目的、意义
1.2.1 研究目的
- 建立统一的网约车业务数据模型(用户、上车区域、行程明细),完成
ridehail建库与 T-Drive 抽样数据初始化。 - 实现前台登录鉴权与侧栏多页面分析,按行政区、月份等条件筛选后输出图表 bundle。
- 实现基于随机森林的小时需求或均时长预测页面,一次请求完成拉数、训练、指标评估与多步预测展示。
- 提供智谱 AI 助手与自研后台对用户、区域、行程三类业务表的增删改查,保证数据可维护、图表可刷新。
1.2.2 研究意义
理论意义上,课题将 Web 应用分层、聚合查询、机器学习回归与大模型问答结合起来,形成可复用的「页面路由 + bundle API + 预测服务」模式。实践意义上,系统可在课堂或答辩环境中一键演示可视化与预测链路,降低对外部商业平台的依赖。社会与教学意义上,有助于理解网约车行程的时空分布、OD 结构与高峰需求,培养 GPS 轨迹处理、可视化工程与预测建模能力。
1.3 课题的国内外研究现状和发展动态
1.3.1 国外研究现状
国外在出租车/网约车需求预测、轨迹挖掘与交互可视化方面积累较早。微软 T-Drive 等项目将大规模 GPS 轨迹公开用于学术研究与方法对比;常见路径是将轨迹切分为行程后导入数据仓库,再以 BI 工具或自研 Web 看板呈现热点与高峰特征。预测方面,统计模型与机器学习(含随机森林、梯度提升等)被用于短时需求估计;深度学习模型在数据充足时表现突出,但对算力与样本质量要求更高。课题级系统往往在准确率与实现成本之间折中,选用可解释、训练成本低的集成学习即可满足演示需求。
1.3.2 国内研究现状
国内高校毕业设计中,基于 Flask/Django 的出行数据分析课题较多,常见组合为 MySQL + ECharts,辅以 pandas 做预处理。部分课题引入 ARIMA、LSTM 等时序模型作为对比,但部署与调参成本较高。管理端有的使用 Django Admin,有的自研轻量 CRUD。本课题选择 Flask + 自研 /admin/,前台交付以随机森林一键预测为主,与 ride-theme 统一视觉,业务语义固定为区域—行程—可视化六模块,避免套用共享单车或地铁课题菜单。
1.3.3 发展趋势
趋势上,行程分析正向「入库—缓存—交互可视化—在线预测—智能问答」一体化演进;前端强调本地化静态资源与弱网可用;预测服务强调一次请求返回指标与图表。本系统在可视化 bundle TTL、随机森林时间留出评估、T-Drive 真实轨迹切分导入与智谱免费模型接入等方面体现了上述工程趋势。
1.4 研究内容
研究内容包括:(1)库表设计与 data_initializer.py 初始化;(2)Flask 路由、Session 登录与侧栏菜单;(3)ride_viz_charts 各可视化 bundle 与筛选条件;(4)随机森林特征构造、训练评估与滚动多步预测;(5)智谱 AI 助手(RideAIAssistant)接入;(6)自研后台 CRUD(users/zones/trips);(7)功能与性能层面的验证。创新点集中在:首页五 KPI + 上车 TOP + 支付占比 + 24h 需求曲线、六维行程可视化(上车热点/OD 流向/行程时长/需求时序/费用结构/支付与载客)+ 版本缓存、随机森林需求/时长双模式一站式预测页、与前台统一主题的自研后台,以及智谱 glm-4-flash 行程问答。
1.5 论文结构安排
第1章介绍背景、目的意义、研究现状与研究内容。第2章说明 Python、Flask、MySQL/PyMySQL、pandas/sklearn、ECharts 与智谱 AI 等相关技术。第3章给出架构、数据流、功能结构、六大模块详细设计与数据库设计。第4章按模块阐述实现流程、核心代码、访问路径与界面图题。第5章给出功能测试用例与性能分析。第6章总结量化成果并展望改进方向。文末为参考文献与致谢。
2 相关技术
2.1 Python编程语言
2.1.1 语言特性与项目选型
Python 语法简洁,生态覆盖 Web、数据处理与机器学习。本项目使用 Python 3.11,依赖见 requirements.txt:Flask、PyMySQL、pandas、numpy、scikit-learn、requests、python-dotenv 等。业务脚本与工具模块均以 UTF-8 源码组织,便于在 Windows 环境下维护。
2.1.2 在本系统中的应用位置
app.py 负责路由与会话;utils/db.py 封装连接与查询;utils/ride_viz_charts.py、utils/index_data.py、models/random_forest_model.py、utils/ai_assistant.py、utils/admin_blueprint.py 分别承担图表聚合、首页看板、随机森林预测、AI 问答与后台。启动时通过 utils/data_initializer.py 的 auto_initialize_data 在空库场景下自动导入 T-Drive 抽样 CSV。
2.2 Flask Web框架
2.2.1 轻量路由与会话
Flask 以装饰器注册路由,适合中小型课题。本系统用 session 保存 userName、avatar_url、is_admin;未登录访问受保护页重定向 /login,访问 /admin 且未满足管理员条件则跳转 /admin/login。根路径 / 与 /login 共用登录视图。
2.2.2 Blueprint 扩展后台
后台以 Blueprint admin_bp 挂载于 /admin,与主应用解耦。页面模板与前台共用 ride-theme 资源,权限通过 admin_required 校验管理员会话,未满足则携带 next 跳转独立后台登录页。
2.3 MySQL与PyMySQL
2.3.1 存储选型
业务数据存放于 MySQL 库 ridehail,字符集 utf8mb4。config.py 中 DB_NAME 默认 ridehail,可通过 .env 覆盖。表结构由 utils/data_initializer.py 中 DDL 创建,并预置 admin/admin123 管理员。
2.3.2 访问封装
utils/db.py 使用 PyMySQL 执行参数化 SQL,query(sql, params, mode) 支持查询与写入。图表、预测与后台列表均通过参数绑定访问,降低拼接风险。ride_trips 对 pickup_datetime、pu_borough、hour 建立索引,支撑按行政区/月份筛选。
2.4 pandas与scikit-learn随机森林
2.4.1 数据处理
预测链路用 pandas 将查询结果整理为含 datetime、total_flow 的升序表,清洗异常值并裁剪负值。可视化侧借助聚合 SQL 直接产出图表序列,减少前端计算负担。T-Drive 切分脚本 scripts/process_tdrive_trips.py 亦使用 pandas 处理 GPS 点列并生成行程 CSV。
2.4.2 随机森林回归
RandomForestPredictor 基于 sklearn.ensemble.RandomForestRegressor:以过去 lookback 个序列点、小时、星期及小时正弦/余弦为特征,按时间顺序留出后 20% 评估 MAE/RMSE/R²,再对未来多步滚动预测。该方案训练快、可解释性较好,适合课题演示。前台交付以随机森林为主,支持「小时订单量」与「小时均时长」两种预测模式。
2.5 ECharts与ride-theme
2.5.1 本地化静态资源
模板 base.html 引用 static/vendor 下 Bootstrap、Bootstrap Icons 与 ECharts 等本地资源,避免依赖外网 CDN,保证离线演示可用。主题样式集中在 static/css/ride-theme.css,主色为琥珀 #c2410c;登录/注册页背景使用 static/img/ride-bg.jpg。
2.5.2 图表交互约定
可视化页通过 static/js/ride_viz_pages.js、ride_chart_helpers.js 拉取 JSON 并渲染柱状图、折线图、饼图、热力图等;提示框使用系列名展示,避免出现无意义的 series0 文案。上车热点等 TOP 类图表保证类目名与数值一致。
2.6 智谱AI与技术特色
2.6.1 智谱 glm-4-flash
utils/ai_assistant.py 中 RideAIAssistant 通过 OpenAI 兼容接口 POST {ZHIPU_BASE_URL}/chat/completions 调用智谱模型,默认 glm-4-flash。密钥写入项目 .env(ZHIPU_API_KEY),不写入论文交付文案。系统提示词约束回答紧扣网约车行程业务(热点、OD、时长、费用、预测等)。免费档适合一问一答演示。
2.6.2 技术特色与创新点
可视化 bundle + 短缓存:ride_viz_charts 以 _cache["version"] 控制失效,TTL 约 120 秒,后台写操作后调用 invalidate_viz_cache(),并联动清空首页缓存。
首页行程看板:utils/index_data.py 提供五 KPI(总行程、平均时长、平均距离、平均费用、行政区数)、上车 TOP、支付占比饼图与 24h 需求曲线。
随机森林一站式预测:/ride/api/rf_predict 一次返回历史曲线、预测曲线与评估指标,支持 demand/duration 双模式。
自研后台:非 Flask-Admin,按 admin_registry.MODULES 声明式配置列表列与表单字段(users/zones/trips)。
前后台登录分离:前台 /login(表单字段 userName),后台 /admin/login,避免管理入口与普通用户入口混淆。
资源本地化与主题统一:vendor 本地化 + ride-theme.css,前后台视觉一致。
T-Drive 真实轨迹切分:保留公开 GPS 轨迹的时空形状,映射到北京行政区与粗网格区域演示配置;费用与支付按国内规则衍生,详见 DATA_SOURCES.md。
3 系统分析与设计
3.1 系统总体设计
3.1.1 系统架构设计
系统采用表现层、业务逻辑层与数据访问层三层结构。表现层为 Jinja2 模板与可视化/预测前端脚本;业务层包括鉴权、首页看板、图表 bundle、随机森林预测、AI 助手与后台 CRUD;数据层为 MySQL ridehail。
图3.1 系统架构图
3.1.2 系统数据流设计
外部角色包括前台用户与管理员。系统输出页面 HTML 与图表/预测 JSON,并将后台维护结果写入数据库;AI 问答依赖智谱接口返回文本。
图3.2 顶层数据流图
图3.3 0层数据流图
3.1.3 系统功能模块设计
结合侧栏与后台菜单,功能划分为六大模块:(1)用户认证;(2)行程多维可视化;(3)数据总览;(4)随机森林需求时长预测;(5)AI智能助手;(6)后台数据管理。首页看板作为可视化入口的补充,在实现章与界面节说明;六类可视化页面归属模块(2)。
图3.4 系统功能结构图
3.2 系统详细设计
3.2.1 用户认证模块设计
模块提供 /login、/register、/logout。登录校验 tbl_user 表用户名与密码(演示环境明文存储,与课题默认账号一致);成功后写入 session["userName"],并可写入头像与 is_admin。注册校验用户名唯一与必填项。未登录访问受保护页重定向登录;若目标为 /admin,则跳转 /admin/login。默认账号 admin/admin123。前台登录表单字段名为 userName。个人中心 /profile 支持改密与头像上传(/upload_avatar)。
3.2.1.1 用户认证流程设计
图3.5 用户认证模块流程图
3.2.2 行程多维可视化模块设计
模块覆盖侧栏六页与首页看板:上车热点 /ride/pickup_heat、OD 流向 /ride/od_flow、行程时长 /ride/duration、需求时序 /ride/demand、费用结构 /ride/fare、支付与载客 /ride/payment;首页 /index 由 get_home_dashboard() 直接渲染 KPI 与图表数据。公共筛选项接口 /ride/api/viz/options,各页分别调用对应 bundle API(如 /ride/api/viz/pickup-heat)。筛选维度为行政区(borough)、月份(month);_where 在已选行政区时以 pu_borough 为准。聚合逻辑集中在 utils/ride_viz_charts.py,带版本缓存。
3.2.2.1 行程多维可视化流程设计
图3.6 行程多维可视化模块流程图
3.2.3 数据总览模块设计
数据总览页 /data_preview 面向表格化浏览与核对,展示行程记录的关键字段(上车区域、上车时间、时长、距离、乘客数、上下车行政区、总额、支付方式、小时等),支持按行政区与日期筛选并分页查看,另提供 /export_data 导出 CSV(最多 5000 条),便于答辩时核对库内样本是否齐全。
3.2.3.1 数据总览流程设计
图3.7 数据总览模块流程图
3.2.4 随机森林需求时长预测模块设计
预测页 /ride/rf_predict 选择行政区、预测模式(demand 小时订单量 / duration 小时均时长)、预测步数与 lookback 后,调用 /ride/api/rf_predict。服务端从 ride_trips 按小时聚合拉取最近最多 2000 条序列,构造滞后特征与日历特征,训练 RandomForestRegressor,用时间留出集计算 MAE/RMSE/R²,再滚动预测未来若干小时,返回历史与预测曲线数据供 ECharts 展示。步数限制约 6–168,lookback 约 12–72。
3.2.4.1 随机森林需求时长预测流程设计
图3.8 随机森林需求时长预测模块流程图
3.2.5 AI智能助手模块设计
助手页 /ride/ai_assistant,接口 /ride/api/ai_ask。后端 RideAIAssistant.ask 组装 system/user/assistant 消息,请求智谱 chat/completions,默认模型 glm-4-flash。用于解答上车热点、OD 流向、高峰需求、时长距离、费用结构、随机森林指标含义等问题。未配置 ZHIPU_API_KEY 时返回明确提示。
3.2.5.1 AI智能助手流程设计
图3.9 AI智能助手模块流程图
3.2.6 后台数据管理模块设计
/admin/login 为独立后台登录;登录成功后进入 /admin/ 概览。子模块覆盖 users、zones、trips,对应表 tbl_user、ride_zones、ride_trips,支持列表搜索、创建、编辑、删除。写操作后调用 invalidate_viz_cache()。权限要求会话为管理员(账号 admin 或 is_admin=1)。菜单定义见 utils/admin_registry.py 的 ADMIN_MENU 与 MODULES。后台亦支持 T-Drive 轨迹重切导入。
3.2.6.1 后台数据管理流程设计
图3.10 后台数据管理模块流程图
3.3 数据库设计
3.3.1 数据库关系设计
数据库名为 ridehail。交付核心业务表:tbl_user(系统账号)、ride_zones(上车区域对照)、ride_trips(行程明细)。行程通过 pu_location_id 关联 ride_zones.location_id,便于热点页展示区域名称。建表逻辑在 utils/data_initializer.py DDL 中;行程时序由 T-Drive 切分 CSV 或启动自动初始化写入。
图3.11 数据库表关系图
表3.1 tbl_user 表结构
| 字段名称 | 字段类型 | 字段说明 | 是否主键 | 是否为空 |
|---|---|---|---|---|
| id | INT | 自增主键 | 是 | 否 |
| user_name | VARCHAR(50) | 用户名(唯一) | 否 | 否 |
| password | VARCHAR(100) | 密码 | 否 | 否 |
| VARCHAR(100) | 邮箱 | 否 | 是 | |
| is_admin | TINYINT | 是否管理员 | 否 | 是 |
| avatar | VARCHAR(255) | 头像路径 | 否 | 是 |
| created_at | TIMESTAMP | 创建时间 | 否 | 是 |
表3.2 ride_zones 表结构
| 字段名称 | 字段类型 | 字段说明 | 是否主键 | 是否为空 |
|---|---|---|---|---|
| location_id | INT | 区域 ID | 是 | 否 |
| zone_name | VARCHAR(80) | 区域名称 | 否 | 否 |
| borough | VARCHAR(40) | 行政区 | 否 | 否 |
| service_zone | VARCHAR(40) | 服务分区 | 否 | 是 |
表3.3 ride_trips 表结构
| 字段名称 | 字段类型 | 字段说明 | 是否主键 | 是否为空 |
|---|---|---|---|---|
| id | INT | 自增主键 | 是 | 否 |
| pickup_datetime | DATETIME | 上车时间 | 否 | 否 |
| dropoff_datetime | DATETIME | 下车时间 | 否 | 是 |
| duration_min | DECIMAL(8,2) | 行程时长(分钟) | 否 | 是 |
| trip_distance | DECIMAL(8,2) | 行程距离(公里) | 否 | 是 |
| passenger_count | TINYINT | 乘客人数 | 否 | 是 |
| pu_location_id | INT | 上车区域 ID | 否 | 是 |
| do_location_id | INT | 下车区域 ID | 否 | 是 |
| pu_borough | VARCHAR(40) | 上车行政区 | 否 | 是 |
| do_borough | VARCHAR(40) | 下车行政区 | 否 | 是 |
| fare_amount | DECIMAL(10,2) | 车费 | 否 | 是 |
| tip_amount | DECIMAL(10,2) | 小费 | 否 | 是 |
| total_amount | DECIMAL(10,2) | 总费用 | 否 | 是 |
| payment_type | TINYINT | 支付类型编码 | 否 | 是 |
| payment_name | VARCHAR(20) | 支付方式名称 | 否 | 是 |
| vendor_id | TINYINT | 车辆标识 | 否 | 是 |
| hour | TINYINT | 小时(0-23) | 否 | 是 |
| day_of_week | TINYINT | 星期几 | 否 | 是 |
| is_weekend | TINYINT | 是否周末 | 否 | 是 |
种子数据方面:启动时 seed_admin() 预置管理员 admin/admin123;ride_zones 与 ride_trips 由 data/processed/beijing_zone_lookup.csv 与 beijing_trips_sample.csv 导入,推荐规模约 398 个区域、15349 条行程。原始 GPS 来自微软 T-Drive 北京样本(约 2008-02-02~2008-02-08);费用与支付方式为按国内规则衍生的演示字段,答辩时需说明,详见 data/DATA_SOURCES.md。
4 系统实现
4.0 系统整体实现流程
实现按「环境与库表 → 鉴权与壳页 → 首页看板与可视化 bundle → 随机森林预测 → AI 助手 → 自研后台 → 联调」推进。配置集中在 config.py / .env(端口 8082、库 ridehail)。
图4.0 系统整体实现流程图
4.1 用户认证模块的实现
登录、注册、退出在 app.py 中实现;登录页使用 ride-theme.css 与 ride-bg.jpg 背景,表单字段为 userName、password,以 JSON 返回校验结果。
功能实现流程设计
图4.1 用户认证模块实现流程图
核心代码实现
# 来源:app.py — 前台登录(节选)
@app.route("/", methods=["GET", "POST"])
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "GET":
nxt = (request.args.get("next") or "").strip()
if nxt.startswith("/admin"):
return redirect(url_for("admin.login", next=nxt))
return render_template("login.html")
return_dict = {"code": "200", "msg": "处理成功", "result": False}
user = db.query(
"select user_name, avatar, is_admin from tbl_user where user_name = %s and password = %s",
[request.form["userName"], request.form["password"]],
"select",
)
if user:
session["userName"] = request.form["userName"]
session["avatar_url"] = user[0][1] or "/static/assets/images/avatar.png"
uname = request.form["userName"]
flag = bool(user[0][2]) if len(user[0]) > 2 and user[0][2] else False
session["is_admin"] = flag or (uname == "admin")
return jsonify(return_dict)
return_dict["code"] = "400"
return_dict["msg"] = "用户名和密码不一致"
return jsonify(return_dict)
功能访问路径
- 前台登录:
http://127.0.0.1:8082/login - 注册:
http://127.0.0.1:8082/register - 退出:
http://127.0.0.1:8082/logout - 个人中心:
http://127.0.0.1:8082/profile - 默认账号:
admin/admin123
界面截图见第 4.7 节图4.9。
4.2 行程多维可视化模块的实现
六类可视化页共用筛选项组件与 bundle API;聚合逻辑在 utils/ride_viz_charts.py,前端由 ride_viz_pages.js 渲染(先就绪 options 再请求图表,行政区与月份联动)。首页 /index 调用 get_home_dashboard() 注入 KPI、上车 TOP、支付占比与 24h 需求曲线。
功能实现流程设计
图4.2 行程多维可视化模块实现流程图
核心代码实现
# 来源:app.py — 可视化路由与 API(节选)
@app.route("/ride/pickup_heat")
def ride_pickup_heat():
return _page("ride_pickup_heat.html", "ride_pickup_heat")
@app.route("/ride/api/viz/pickup-heat")
def ride_api_pickup_heat():
from utils.ride_viz_charts import pickup_heat_bundle
a = _viz_args()
return jsonify({"success": True, "ok": True, "data": pickup_heat_bundle(a["borough"], a["month"])})
# 来源:utils/ride_viz_charts.py — 上车热点 bundle 与缓存(节选)
def invalidate_viz_cache():
"""图表短缓存失效。"""
_cache["version"] += 1
_cache["items"].clear()
try:
from utils.index_data import invalidate_index_cache
invalidate_index_cache()
except Exception:
pass
def pickup_heat_bundle(borough="", month="", top_n=15):
"""上车区域订单量 TOP。"""
key = f"heat:{borough}:{month}:{top_n}"
def build():
where, params = _where(borough, month)
sql = f"""
SELECT COALESCE(z.zone_name, CONCAT('区域', t.pu_location_id)) AS zname,
COUNT(*) AS cnt,
AVG(t.duration_min) AS avg_dur,
AVG(t.trip_distance) AS avg_dist
FROM ride_trips t
LEFT JOIN ride_zones z ON z.location_id = t.pu_location_id
WHERE {where}
GROUP BY t.pu_location_id, z.zone_name
ORDER BY cnt DESC
LIMIT %s
"""
rows = db.query(sql, params + [int(top_n)], "select") or []
labels = [r[0] for r in rows]
return {
"top_count": {"labels": labels, "values": [safe_int(r[1]) for r in rows]},
"avg_duration": {"labels": labels, "values": [round(safe_float(r[2]), 1) for r in rows]},
"avg_distance": {"labels": labels, "values": [round(safe_float(r[3]), 2) for r in rows]},
}
return _bundle(key, build)
# 来源:utils/index_data.py — 首页看板(节选)
def get_home_dashboard():
"""首页一次取出 KPI + 三图数据。"""
now = time.time()
if _cache["item"] and now - _cache["ts"] < _TTL:
return _cache["item"]
kpi_row = db.query(
"""
SELECT COUNT(*), AVG(duration_min), AVG(trip_distance), AVG(total_amount),
COUNT(DISTINCT pu_borough)
FROM ride_trips
""",
[],
"select",
)
r = kpi_row[0] if kpi_row else (0, 0, 0, 0, 0)
kpi = {
"total_trips": safe_int(r[0]),
"avg_duration": round(safe_float(r[1]), 1),
"avg_distance": round(safe_float(r[2]), 2),
"avg_fare": round(safe_float(r[3]), 1),
"borough_count": safe_int(r[4]),
}
# top_pickup / payment / hourly ...
return data
功能访问路径
- 首页:
/index - 上车热点:
/ride/pickup_heat - OD 流向:
/ride/od_flow - 行程时长:
/ride/duration - 需求时序:
/ride/demand - 费用结构:
/ride/fare - 支付与载客:
/ride/payment - 筛选项 API:
GET /ride/api/viz/options - 各页 bundle API:
/ride/api/viz/pickup-heat、od-flow、duration、demand、fare、payment
界面截图见第 4.7 节图4.10~图4.16。
4.3 数据总览模块的实现
数据总览在 app.py 的 /data_preview 路由中实现,查询 ride_trips 关联 ride_zones 并渲染表格;支持按行政区、日期筛选与 CSV 导出。
功能实现流程设计
图4.3 数据总览模块实现流程图
核心代码实现
# 来源:app.py — 数据总览路由(节选)
@app.route("/data_preview")
def data_preview():
if not session.get("userName"):
return redirect("/login")
page = request.args.get("page", 1, type=int)
per_page = request.args.get("per_page", 20, type=int)
borough = request.args.get("city", "")
date_filter = request.args.get("date", "")
where_conditions = []
params = []
if borough:
where_conditions.append("t.pu_borough = %s")
params.append(borough)
if date_filter:
where_conditions.append("DATE(t.pickup_datetime) = %s")
params.append(date_filter)
where_clause = (" WHERE " + " AND ".join(where_conditions)) if where_conditions else ""
tableData = db.query(
f"""
SELECT COALESCE(z.zone_name, CONCAT('区域', t.pu_location_id)) AS zname,
t.pickup_datetime, t.duration_min, t.trip_distance, t.passenger_count,
t.pu_borough, t.do_borough, t.total_amount, t.payment_name, t.hour
FROM ride_trips t
LEFT JOIN ride_zones z ON z.location_id = t.pu_location_id
{where_clause}
ORDER BY t.pickup_datetime DESC
LIMIT %s OFFSET %s
""",
params + [per_page, offset],
"select",
)
return render_template("data_preview.html", tableData=tableData, ...)
功能访问路径
- 数据总览:
http://127.0.0.1:8082/data_preview - CSV 导出:
http://127.0.0.1:8082/export_data
界面截图见第 4.7 节图4.17。
4.4 随机森林需求时长预测模块的实现
页面 ride_rf_predict.html,算法类位于 models/random_forest_model.py,接口 /ride/api/rf_predict 一次完成训练与预测,支持 demand(小时订单量)与 duration(小时均时长)两种模式。
功能实现流程设计
图4.4 随机森林需求时长预测模块实现流程图
核心代码实现
# 来源:models/random_forest_model.py — 特征与训练(节选)
class RandomForestPredictor:
def __init__(self, lookback=24, n_estimators=80, random_state=42):
self.lookback = int(lookback)
self.n_estimators = int(n_estimators)
self.model = None
def _feature_row(self, lag_values, ts):
hour = int(ts.hour)
dow = int(ts.dayofweek)
hour_sin = np.sin(2 * np.pi * hour / 24.0)
hour_cos = np.cos(2 * np.pi * hour / 24.0)
return np.asarray(list(lag_values) + [hour, dow, hour_sin, hour_cos], dtype=float)
def train(self, train_data):
df = self._prepare_frame(train_data)
flows = df["total_flow"].to_numpy(dtype=float)
times = df["datetime"].tolist()
X, y = self._make_xy(flows, times)
split = max(self.lookback, int(len(y) * 0.8))
X_train, y_train = X[:split], y[:split]
X_test, y_test = X[split:], y[split:]
self.model = RandomForestRegressor(
n_estimators=self.n_estimators, random_state=self.random_state,
n_jobs=-1, max_depth=12, min_samples_leaf=2,
)
self.model.fit(X_train, y_train)
# 留出集评估 MAE/RMSE/R²,全量重训供滚动预测
...
# 来源:app.py — 一键预测 API(节选)
@app.route("/ride/api/rf_predict", methods=["POST"])
def ride_api_rf_predict():
data = request.get_json() or {}
borough = (data.get("borough") or "").strip()
mode = (data.get("mode") or "demand").strip()
steps = max(6, min(int(data.get("steps") or 24), 168))
lookback = max(12, min(int(data.get("lookback") or 24), 72))
if mode == "duration":
metric_sql = "AVG(duration_min)"
else:
metric_sql = "COUNT(*)"
sql = f"""
SELECT DATE_FORMAT(pickup_datetime, '%%Y-%%m-%%d %%H:00:00') AS ts, {metric_sql} AS val
FROM ride_trips
WHERE {where}
GROUP BY DATE_FORMAT(pickup_datetime, '%%Y-%%m-%%d %%H:00:00')
ORDER BY ts DESC
LIMIT 2000
"""
model = RandomForestPredictor(lookback=lookback, n_estimators=80)
metrics = model.train(df)
forecast = model.predict(steps=steps)
return jsonify({
"success": True,
"metrics": metrics,
"history": {"labels": hist_labels, "values": hist_values},
"forecast": {"labels": fut_labels, "values": fut_values},
"series_name": series_name,
"scope": borough or "全城",
})
功能访问路径
- 预测页:
http://127.0.0.1:8082/ride/rf_predict - 预测 API:
POST /ride/api/rf_predict
界面截图见第 4.7 节图4.18。
4.5 AI智能助手模块的实现
页面 ride_ai_assistant.html,服务类 utils/ai_assistant.py 中的 RideAIAssistant,接口 /ride/api/ai_ask。
功能实现流程设计
图4.5 AI智能助手模块实现流程图
核心代码实现
# 来源:utils/ai_assistant.py — 智谱调用(节选)
class RideAIAssistant:
def __init__(self):
self.api_key = (os.getenv("ZHIPU_API_KEY") or "").strip()
self.base_url = (os.getenv("ZHIPU_BASE_URL")
or "https://open.bigmodel.cn/api/paas/v4").rstrip("/")
self.model = os.getenv("ZHIPU_MODEL", "glm-4-flash").strip()
def ask(self, question: str, history=None) -> str:
if not self.api_key:
return "未配置智谱 API Key,请在 .env 中设置 ZHIPU_API_KEY。"
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
for item in history or []:
role = (item.get("role") or "").strip()
content = (item.get("content") or "").strip()
if role in ("user", "assistant") and content:
messages.append({"role": role, "content": content})
messages.append({"role": "user", "content": str(question).strip()})
url = f"{self.base_url}/chat/completions"
headers = {"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"}
payload = {"model": self.model, "messages": messages,
"temperature": 0.7, "max_tokens": 2048}
resp = requests.post(url, headers=headers, json=payload, timeout=self.timeout)
...
# 来源:app.py — AI 问答路由(节选)
@app.route("/ride/api/ai_ask", methods=["POST"])
def ride_api_ai_ask():
from utils.ai_assistant import RideAIAssistant
payload = request.get_json() or {}
bot = RideAIAssistant()
answer = bot.ask(payload.get("question") or "", payload.get("history") or [])
return jsonify({"success": True, "answer": answer})
功能访问路径
- AI 助手:
http://127.0.0.1:8082/ride/ai_assistant - 问答 API:
POST /ride/api/ai_ask
界面截图见第 4.7 节图4.19。
4.6 后台数据管理模块的实现
后台 Blueprint 注册于 app.py:app.register_blueprint(admin_bp)。模块定义见 utils/admin_registry.py,路由见 utils/admin_blueprint.py。
功能实现流程设计
图4.6 后台数据管理模块实现流程图
核心代码实现
# 来源:utils/admin_registry.py — 模块声明(节选)
ADMIN_MENU = [
("index", "数据概览", "bi-speedometer2"),
("users", "用户管理", "bi-people"),
("zones", "上车区域", "bi-geo-alt"),
("trips", "行程明细", "bi-list-ul"),
]
MODULES = {
"users": {"label": "用户", "table": "tbl_user", "pk": "id", ...},
"zones": {"label": "上车区域", "table": "ride_zones", "pk": "location_id", ...},
"trips": {"label": "行程明细", "table": "ride_trips", "pk": "id", ...},
}
# 来源:utils/admin_blueprint.py — 后台登录与权限(节选)
admin_bp = Blueprint("admin", __name__, url_prefix="/admin")
def admin_required(view):
@wraps(view)
def wrapped(*args, **kwargs):
if not _is_admin_user():
flash("请使用管理员账号登录后台", "warning")
return redirect(url_for("admin.login", next=request.path))
return view(*args, **kwargs)
return wrapped
功能访问路径
- 后台登录:
http://127.0.0.1:8082/admin/login - 后台首页:
http://127.0.0.1:8082/admin/ - 模块:用户 / 上车区域 / 行程明细
界面截图见第 4.7 节图4.20、图4.21。
4.7 用户界面实现
界面基于 templates/base.html 侧栏布局与 ride-theme.css(主色 #c2410c)。侧栏分组为「行程洞察」(六类可视化)、「数据与预测」(数据总览、随机森林、AI 助手)、「个人信息」。首页 /index 展示五 KPI、上车 TOP、支付占比与 24h 需求曲线;可视化、预测、AI、后台分别对应独立模板。
功能实现流程设计
图4.7 用户界面功能实现流程图
图4.9 登录界面

图4.10 首页总览界面

图4.11 上车热点界面

图4.12 OD流向界面

图4.13 行程时长界面

图4.14 需求时序界面

图4.15 费用结构界面

图4.16 支付与载客界面

图4.17 数据总览界面

图4.18 随机森林预测界面

图4.19 AI助手界面

图4.20 后台管理界面

图4.21 后台登录界面

4.8 系统集成与部署
功能实现流程设计
图4.8 系统集成与部署功能实现流程图
部署步骤简述:
- 安装依赖:
pip install -r requirements.txt - 创建 MySQL 库
ridehail,配置.env中数据库账号 - 下载并处理 T-Drive 数据:
python scripts/fetch_beijing_tdrive.pypython scripts/process_tdrive_trips.py --sample 80000python scripts/import_tlc_trips.py
或确保data/processed/beijing_trips_sample.csv与beijing_zone_lookup.csv存在,空库启动时auto_initialize_data自动导入
- 配置
.env(可选ZHIPU_API_KEY) - 启动:
python app.py(端口 8082) - 访问:前台
http://127.0.0.1:8082/login,后台http://127.0.0.1:8082/admin/login,账号admin/admin123
数据来源说明见项目内 data/DATA_SOURCES.md:轨迹来自微软 T-Drive 北京公开 GPS;行程由时间缺口与里程切分;行政区由经纬度框映射;费用与支付方式为演示衍生字段。
5 系统测试
5.1 系统功能测试
项目提供 scripts/test_all_features.py 冒烟测试脚本,基于 Flask test_client 对登录、页面、API 与后台进行自动化验证。在本机 MySQL 已导入约 15349 条行程的前提下,执行 python scripts/test_all_features.py,24 项全部 PASS。
5.1.1 用户认证功能测试用例
| 编号 | 说明 | 条件 | 操作步骤 | 预期结果 | 实际结果 |
|---|---|---|---|---|---|
| TC-A01 | 正确登录 | 库中存在 admin/admin123 | POST /login,输入 admin/admin123 | 返回 code=200 | 通过 |
| TC-A02 | 错误密码 | 账号存在 | 输入错误密码提交 | 返回 code=400 | 通过 |
| TC-A03 | 注册新用户 | 用户名未占用 | /register 填写信息并提交 | 注册成功可登录 | 通过 |
| TC-A04 | 未登录拦截 | 清空会话 | 直接 GET /index | 302 跳转 /login | 通过 |
| TC-A05 | 退出登录 | 已登录 | 点击退出 | 会话清空并回登录页 | 通过 |
5.1.2 数据管理功能测试用例
| 编号 | 说明 | 条件 | 操作步骤 | 预期结果 | 实际结果 |
|---|---|---|---|---|---|
| TC-B01 | 后台登录 | admin 账号 | 打开 /admin/login 登录 | 进入后台概览 | 通过 |
| TC-B02 | 用户列表 | 已登后台 | 打开用户管理 | 显示 tbl_user 列表 | 通过 |
| TC-B03 | 新增区域 | 已登后台 | 上车区域管理中新增一条 | 保存成功并可检索 | 通过 |
| TC-B04 | 编辑行程 | 已有行程 | 修改时长并保存 | 列表显示更新后数据 | 通过 |
| TC-B05 | 删除行程 | 已有记录 | 删除 ride_trips 记录 | 写库成功,可视化缓存失效 | 通过 |
5.1.3 核心业务功能测试用例
| 编号 | 说明 | 条件 | 操作步骤 | 预期结果 | 实际结果 |
|---|---|---|---|---|---|
| TC-C01 | 首页访问 | 已登录 | 打开 /index | 五 KPI、TOP、支付、24h 曲线正常 | 通过 |
| TC-C02 | 上车热点 | 库有行程 | 打开 /ride/pickup_heat | 图表显示 TOP 区域订单 | 通过 |
| TC-C03 | OD 流向 | 库有 pu/do_borough | 打开 /ride/od_flow | OD 柱状与行政区饼图可读 | 通过 |
| TC-C04 | 随机森林预测 | 历史充足 | /ride/rf_predict 点击预测 | 返回指标与预测曲线 | 通过 |
| TC-C05 | AI 问答 | 已配置 Key | /ride/ai_assistant 提问 | 返回中文回答 | 通过 |
5.1.4 数据分析功能测试用例
| 编号 | 说明 | 条件 | 操作步骤 | 预期结果 | 实际结果 |
|---|---|---|---|---|---|
| TC-D01 | 行程时长 | 有 duration_min | /ride/duration | 时长分箱与行政区对比正确 | 通过 |
| TC-D02 | 需求时序 | 有 hour 字段 | /ride/demand | 日订单与 24h 曲线可读 | 通过 |
| TC-D03 | 费用结构 | 有 total_amount | /ride/fare | 行政区均价与小费占比正确 | 通过 |
| TC-D04 | 支付与载客 | 有 payment_name | /ride/payment | 支付饼图与载客柱状正确 | 通过 |
| TC-D05 | 数据总览筛选 | 库有记录 | /data_preview 改条件 | 表格按条件刷新 | 通过 |
5.1.5 系统集成功能测试用例
| 编号 | 说明 | 条件 | 操作步骤 | 预期结果 | 实际结果 |
|---|---|---|---|---|---|
| TC-E01 | 前后台联通 | 服务已启动 8082 | 后台改行程后刷新可视化 | 图表反映新数据 | 通过 |
| TC-E02 | 后台写后缓存 | 改 ride_trips | 再打开上车热点 | 结果更新而非旧缓存 | 通过 |
| TC-E03 | viz API 联通 | 已登录 | GET 七个 /ride/api/viz/* | 均返回 ok 与 data | 通过 |
| TC-E04 | 端口与入口 | 本机环境 | python app.py | 监听 8082 可访问 | 通过 |
| TC-E05 | 静态资源本地 | 断外网 | 打开可视化页 | ECharts/样式仍可用 | 通过 |
5.1.6 用户界面功能测试用例
| 编号 | 说明 | 条件 | 操作步骤 | 预期结果 | 实际结果 |
|---|---|---|---|---|---|
| TC-F01 | 侧栏高亮 | 已登录 | 依次点击各菜单 | active 状态与页面一致 | 通过 |
| TC-F02 | 主题样式 | 已登录 | 查看首页与后台 | ride-theme 与 ride-bg 生效 | 通过 |
| TC-F03 | 图表悬停 | 可视化页 | 鼠标悬停系列 | tip 显示名称与数值 | 通过 |
| TC-F04 | 预测页控件 | 预测页 | 改步数再预测 | 曲线长度随步数变化 | 通过 |
| TC-F05 | 后台登录页 | 未登后台 | 打开 /admin/login | 独立登录界面展示 | 通过 |
5.2 系统性能测试
5.2.1 响应时间性能分析
在本地演示数据规模(约 15349 条行程、398 个区域)下,登录接口与普通页面渲染通常在数百毫秒内完成;可视化 bundle 首次查询受 SQL 聚合影响,二次访问因 TTL 缓存明显加快;随机森林一键预测受样本长度与 n_estimators=80 影响,一般可在数秒内返回,满足课题演示。
5.2.2 并发性能测试
课题场景以单人/少量并发为主。Flask 开发服务器适合演示;若需更高并发,可改为 Waitress/gunicorn 等 WSGI 部署,并对可视化查询加索引与缓存。智谱免费档存在 RPM 限制,AI 助手宜一问一答演示。
5.2.3 数据库性能测试
ride_trips 在 pickup_datetime、pu_borough、hour 等字段建有索引,支撑按行政区/月份筛选。区域对照表 ride_zones 以 location_id 为主键,JOIN 热点页查询开销可控。大批量 T-Drive 导入时走批量写入,避免逐条插入拖慢初始化。
5.2.4 性能优化措施
- 可视化 bundle 短时缓存(约 120 秒)与版本失效;首页看板 TTL 约 90 秒。
- 预测接口限制历史条数上限(2000)与步数/lookback 范围,控制训练耗时。
- 静态资源本地化,减少外网依赖。
- 后台写操作后主动
invalidate_viz_cache()(联动首页缓存),避免脏读与过久缓存并存。 - SQL 参数化与必要索引,降低全表扫描概率。
6 总结与展望
6.1 总结
本文完成了基于 Flask 的城市网约车行程分析与时长需求预测系统的设计与实现。系统以 MySQL 库 ridehail 存储用户、上车区域与行程明细,前台提供登录鉴权、首页五 KPI 看板、六类行程可视化(上车热点、OD 流向、行程时长、需求时序、费用结构、支付与载客)、数据总览、随机森林一键预测(需求/时长双模式)与智谱 AI 助手(RideAIAssistant / glm-4-flash),后台提供独立登录与用户/区域/行程三类 CRUD。功能模块约六大业务模块(认证、可视化、总览、预测、AI、后台),入口 app.py 运行于端口 8082,默认账号 admin/admin123。主数据来自微软 T-Drive 北京 GPS 轨迹切分,推荐规模约 15349 条行程、398 个区域;费用与支付为演示衍生字段。自动化冒烟测试 test_all_features.py 共 24 项全部通过。实践表明,该方案结构清晰、部署轻量,能够支撑毕业设计答辩与教学演示。
6.2 展望
后续可在不改变现有交付主线的前提下,扩展更细粒度的运力调度仿真、优化随机森林特征与超参搜索,并将 AI 助手与库内聚合统计做更深度的数据接地,使问答回答更具业务针对性。生产环境可进一步强化密码哈希、权限分级与 WSGI 部署。若引入更新年份的网约车订单明细,可在保持表结构语义的前提下替换导入脚本,使区域地理与运营指标更贴近实际运维场景。
参考文献
[1] 张海藩, 牟永敏. 软件工程导论[M]. 北京: 清华大学出版社, 2013.
[2] Grinberg M. Flask Web Development[M]. 2nd ed. Sebastopol: O’Reilly Media, 2018.
[3] 王珊, 萨师煊. 数据库系统概论[M]. 北京: 高等教育出版社, 2014.
[4] McKinney W. Python for Data Analysis[M]. 3rd ed. Sebastopol: O’Reilly Media, 2022.
[5] Pedregosa F, et al. Scikit-learn: Machine Learning in Python[J]. Journal of Machine Learning Research, 2011, 12: 2825-2830.
[6] Breiman L. Random Forests[J]. Machine Learning, 2001, 45(1): 5-32.
[7] Apache ECharts 官方文档[EB/OL]. https://echarts.apache.org/
[8] 智谱 AI 开放平台文档[EB/OL]. https://open.bigmodel.cn/
[9] Yuan J, et al. T-Drive: Driving Directions Based on Taxi Trajectories[C]//ACM SIGSPATIAL GIS, 2010.
[10] Microsoft Research: T-Drive Trajectory Data Sample[EB/OL]. https://www.microsoft.com/en-us/research/publication/t-drive-trajectory-data-sample/
[11] 李航. 统计学习方法[M]. 北京: 清华大学出版社, 2019.
[12] PyMySQL Documentation[EB/OL]. https://pymysql.readthedocs.io/
[13] Flask Documentation[EB/OL]. https://flask.palletsprojects.com/
致谢
本科阶段的学习与本次毕业设计即将告一段落。感谢指导老师在选题、系统设计与论文撰写过程中给予的耐心指导与严格要求,使课题能够紧扣现有代码实现,避免空泛论述。感谢同学们在联调演示、界面核对与问题讨论中提供的帮助。感谢家人一直以来的理解与支持。通过本系统的开发,对 Flask Web 开发、MySQL 数据建模、GPS 轨迹切分、ECharts 可视化与随机森林需求/时长预测有了更完整的实践认识。文中若有不足之处,恳请各位老师批评指正。

294

被折叠的 条评论
为什么被折叠?



