1. 这个选题为什么值得做:需求与价值拆解
1.1 电商用户行为数据:最典型的大数据场景
淘宝用户购物数据在我看来是所有大数据入门场景里最“教科书”的一个。它天然具备高维、稀疏、强时序三个特征:一条原始行为记录里至少包含用户ID、商品ID、类目ID、行为类型(比如浏览pv、收藏fav、加购cart、购买buy)和时间戳,字段虽然不多,但量级一上来就是千万级甚至亿级。这种数据和金融风控、物联网日志、内容推荐的数据结构非常相似,学会处理它,后面换任何业务场景都只是换表名而已。
很多同学一开始看到“淘宝用户购物可视化与行为预测”这个标题,第一反应是“这不是爬虫吗?”。说实话,我刚开始也这么想。但实际做下来会发现,真正的难点不在爬数据,而在怎么把一堆零散的点击日志变成有业务含义的指标和可训练的样本。这里我强烈建议不要直接爬淘宝,一是合规风险高,二是反爬机制会让你浪费大量时间。公开的UserBehavior数据集(阿里天池就有)完全够用,做毕业设计的体量不需要去硬刚真实网页。
行为预测的业务价值也很直观。电商平台最关心的一件事就是转化率:来了100个访客,最后到底有几个人下单?平台能不能提前识别出“这个用户最近可能要买某类商品”?如果能做到,就可以做精准优惠券、商品推荐、库存调度。放到毕业设计里,你只需要回答一个简化问题:给定用户过去一段时间的浏览、收藏、加购序列,预测他下一步会不会购买。这个问题能讲清楚,答辩老师的核心问题基本就过关了。
1.2 一个系统覆盖“大数据+深度学习+可视化”三条主线
毕设评审最看重的几点,我总结为工程完整度、算法理解度、呈现效果。很多系统要么只做了数据分析和可视化,没有算法;要么只训练了一个模型,连网页都没有。而这个题目恰好把三条线串在一起:Django负责后端和业务逻辑,深度学习负责行为预测,ECharts负责数据可视化。你一个人就能走通“数据清洗→特征工程→模型训练→接口服务→前端展示”的完整闭环,这在答辩时是非常大的加分项。
往深了说,这个系统还可以延伸到用户画像、商品推荐、复购预测、实时营销等多个方向。毕设阶段你可以只做购买行为预测,但代码结构上留好扩展位,以后求职想包装成推荐系统项目也顺理成章。网上那些“附源码+文档+调试服务”的版本很多,但我建议至少把核心代码自己敲一遍,尤其是数据预处理和模型训练脚本,面试官很爱追问这两块的细节。
1.3 谁适合选这个题目
如果你是那种Python语法熟悉但没系统接触过深度学习的学生,这个题目的友好之处在于它不需要你发明新模型。淘宝用户行为预测的主流做法非常成熟,网上能找到很多参考,你要做的是把LSTM、DeepFM这类模型应用到自己的数据上,再解释清楚为什么这么选。我见过不少零基础的同学两三天就能跑通一个基础版模型,真正花时间的是数据清洗和Django对接。
如果你本来目标就是数据挖掘或推荐系统方向的岗位,这个项目简直是天然的简历素材。它既有时序特征处理,又有模型训练和评估,还有服务化部署和可视化,几乎把日常数据分析工作流里最核心的环节都覆盖了。选这个题目,本质上是花一个毕设周期,提前体验一遍工业界“用户行为数据→决策模型→业务产品”的完整链路。
2. 系统整体设计:架构与技术选型
2.1 功能模块怎么划分
我觉得做毕设最忌讳一上来就写代码,先把功能模块切清楚,后面能省一半时间。这个系统可以拆成四个模块:
- 数据接入与清洗模块:负责读取原始csv日志、处理缺失值、转换时间戳、行为类型映射、用户和商品抽样。
- 行为预测模块:做特征工程,训练深度学习模型(LSTM/DeepFM),保存模型文件,对外提供预测接口。
- 可视化展示模块:提供总览大屏、用户行为漏斗、商品热销排行、活跃时段分布、未来购买概率TOP用户列表。
- 用户与权限模块:用Django Admin做简单的后台管理,给系统加登录和权限控制。
模块切好以后,开发和调试都能并行推进。比如我先把数据预处理脚本跑通,把特征文件存成csv,再让深度学习脚本读这个csv训练模型;Django那边可以先把可视化页面写出来,用假数据渲染,等模型接口好了再对接真预测结果。这样即使中间某一步卡住,也不会让整个项目停滞。
2.2 为什么选Django而不是Flask或Spring Boot
这个题目里的关键词“django”不是随便选的。Flask虽然轻量,但做这种需要后台管理、用户认证、ORM建表的系统,还是要自己装不少扩展。Django自带Admin后台、用户认证、模板引擎和ORM,对毕业设计的开发效率提升非常明显。比如我想在后台给管理员加一个“重新训练模型”的按钮,用Django Admin几行配置就能搞定;如果用Flask,从表单到路由、权限、日志都要自己写,工作量会大很多。
Spring Boot也是很多同学会纠结的选项,它对大数据生态支持好,但Java的学习成本比Python高。这个题目的算法部分用到TensorFlow或PyTorch,属于Python生态,用Django可以让前后端和算法语言统一,省去跨语言调用的麻烦。实测下来,Django跑一个中小型数据可视化系统性能完全够用,真正耗时的模型推理放到后台任务里异步执行就可以,不需要上微服务那套复杂架构。
2.3 数据库设计与数据流向
数据库设计直接决定你后面写代码痛不痛快。我的做法是三张核心表:
- User表:user_id、gender、age_level、city_level,用户的静态属性。
- Product表:product_id、category_id、brand_id,商品的基础信息。
- Behavior表:id、user_id(外键)、product_id(外键)、behavior_type、timestamp,行为日志。
最核心的是Behavior表,它承担几乎所有特征计算。注意它不是一张“当前状态表”,而是一张时序流水表,每天都会产生大量新记录。做可视化时,直接查Behavior表聚合出“今日PV/UV/下单量”就很快;做模型特征时,也是从这个表里按user_id分组提取最近N天的行为序列。
数据流大致是这样:原始csv先经过pandas清洗,写入MySQL的Behavior表;Django通过ORM查询统计数据供可视化接口使用;训练脚本从MySQL里读样本构造特征,训练完成后把模型文件放好;预测接口读取请求里的用户特征,经过同样的特征处理流程,输入模型得到购买概率。这套链路里,Redis可以放在中间做缓存,比如把热榜数据缓存起来,减轻数据库压力。
这里提一个Django ORM的小技巧:删除Behavior表中某个用户的数据,不需要写SQL,直接用Behavior.objects.filter(user_id=xxx).delete()。很多人会忘记ORM的删除操作返回的是一个元组(deleted_count, {'app.Behavior': count}),调试的时候看到这个结果才知道删了多少行。这类细节虽然小,但真能帮你节省排查时间。
2.4 前后端交互与实时推送
毕设阶段不需要做太复杂的前后端分离。我是先用Django模板直接渲染页面,把ECharts要的数据结构在view里组装好,传到模板里,再让JavaScript初始化图表。这样做的好处是少写一套API文档,开发效率最高。如果有余力,再上Django REST Framework做一套json接口,为以后扩展移动端或小程序留空间。
这里顺便回答一个很多人私信问的问题:后台数据更新后,网页怎么自动刷新?这就是热搜词里“python django websocket实现后台有数据前端推送”的场景。传统做法是前端轮询接口,每5秒请求一次,简单但不优雅。更体面的做法是用Django Channels实现WebSocket,后端感知到新行为数据后主动推给前端,ECharts再更新图表。考虑到毕设时间,我建议先用轮询,系统做完以后再把某个图表升级成WebSocket实时推送,既贴合业务又能展示技术深度。Redis在中间可以作为消息代理,配合常用的Redis可视化客户端,可以直观看到消息Queue里的数据是否被消费掉。
3. 核心算法与模型构建:行为预测怎么做
3.1 特征工程:从原始点击日志到模型输入
行为预测最容易被忽视却又最影响效果的,就是特征工程。直接拿原始行为日志丢给深度学习模型是行不通的,模型需要的是提取后的特征,或者至少是结构化的序列。
我的做法是把特征分成四类:
- 用户基础特征:性别、年龄层次、城市层次,这部分是静态的。
- 统计特征:过去7天浏览商品数、收藏商品数、加购次数、购买次数,行为总时长跨度。
- 商品偏好特征:用户最常浏览的Top3类目,最近一次购买的类目。
- 序列特征:把用户最近20次行为按时间排序,每个行为映射成一个整数编号,比如浏览=0、收藏=1、加购=2、购买=3;同时记录行为之间的时间间隔序列。
标签的构造也很关键。我选择“未来3天内是否购买”作为二分类目标,正样本为1,负样本为0。淘宝用户行为是典型的长尾分布,大部分用户只看不买,所以正负样本比例经常能到1:20甚至更低,后面一定要处理。
特征工程做完以后,可以存成两个文件:train.csv和valid.csv。每一行是一个用户样本,列包括前面提到的所有特征,最后一列是label。这样深度学习脚本只需要读csv,不需要回去查数据库,训练速度会快很多。
3.2 模型怎么选:LSTM还是DeepFM
市面上常见的用户行为预测模型主要分两类。一类是以LSTM、GRU为代表的序列模型,专门处理“用户先看了A,又看了B,最后加购了C”这种先后关系;另一类是以DeepFM、Wide&Deep为代表的深度推荐模型,擅长捕捉类别特征的交叉组合,比如“女装类目+收藏行为”这种组合对购买的刺激。
对毕设来说,我推荐用LSTM加一层注意力机制作为主模型。理由很直接:淘宝用户行为的核心信息藏在“行为顺序”里,浏览、收藏、加购、购买这四种行为有强烈的先后依赖,LSTM对这种时序依赖的建模能力比DeepFM更直观,答辩时也更容易讲清楚为什么选它。DeepFM当然也很好,但需要做的特征交叉分析偏多,反而容易把自己绕进去。
这里还想提醒一句:不要为了追求高分模型把毕设做成调参大战。你的目标不是刷到0.99的AUC,而是完整地展示“为什么会选这个模型、数据怎么喂进去、结果怎么评估、预测结果怎么用”。LSTM+Attention的基线模型做到0.85左右的AUC,已经足够支撑整个毕设的合理性和深度。
3.3 训练流程与评估指标
训练流程里最容易犯的错误是数据泄露。很多人直接把用户行为随机切成训练集和测试集,结果同一个用户的一部分记录在训练集、一部分在测试集,模型“见过”这个用户了,预测分数虚高,答辩时一问就露馅。正确做法是按时间切分:比如取前7天的行为构造特征,训练模型预测第8天到第10天是否购买。这样才符合真实的“用历史预测未来”场景。
正负样本不平衡也要处理。我用的是两种方式结合:一是对负样本做下采样,让正负比例控制在1:5左右;二是在训练时给正样本更高的class_weight。评估指标不能只看Accuracy,因为如果99%是负样本,全预测成负样本也能有99%准确率。要重点看AUC(ROC曲线下面积),它不受阈值影响,能真实反映模型排序能力。我实际跑下来,LSTM基线模型的AUC大概在0.84到0.88之间,召回率在选择性阈值下能到0.45以上,对毕设来说完全够用。
下面是一段简化的Keras模型训练代码,我建议动手敲一遍而不是直接复制:
from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Embedding, LSTM, Dense, Attention, Concatenate # 序列特征输入:行为序列长度固定为20 seq_input = Input(shape=(20,), name='seq_input') # 特征输入:统计特征+用户属性,维度为 example_feature_dim feat_input = Input(shape=(feature_dim,), name='feat_input') embed = Embedding(input_dim=4, output_dim=8, mask_zero=False)(seq_input) lstm_out = LSTM(units=32, return_sequences=False)(embed) # 将序列特征和统计特征拼接 concat = Concatenate()([lstm_out, feat_input]) dense1 = Dense(32, activation='relu')(concat) output = Dense(1, activation='sigmoid')(dense1) model = Model(inputs=[seq_input, feat_input], outputs=output) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['AUC'])训练时使用EarlyStopping,patience设为3,监控验证集AUC。我的经验是LSTM训练不需要太多epoch,10到15轮基本收敛,再多的轮次只会过拟合。
3.4 模型如何交给Django调用
模型训练完不是放到文件夹里就结束了,Django要能加载并调用它。最直接的方式是用Keras的load_model加载.h5或.keras文件。但这里有个性能坑:如果每次请求都加载一次模型,内存里会反复创建对象,并发一高页面直接卡死。正确做法是让模型在Django进程启动时只加载一次,之后所有请求复用同一个对象。
我用了一个很简单的单例封装:
from tensorflow.keras.models import load_model from functools import lru_cache @lru_cache(maxsize=1) def get_model(): return load_model('ml_models/best_model.keras')预测接口的逻辑也不复杂:先根据请求里的user_id从Behavior表取出最近行为序列和统计特征,做同样的特征工程,再调用get_model().predict()得到购买概率。返回给前端的除了预测概率,最好还带上解释性字段,比如“该用户最近浏览主要集中在美妆类目”,这样可视化页面也能顺带展示。
4. 可视化大屏与指标设计
4.1 大屏该放哪些图
可视化不是把图表堆满屏幕就好,而是要回答业务问题。我设计大屏时先问自己:运营人员最关心什么?答案是总体销量、用户活跃情况、转化漏斗、热门商品类目。
所以我最终选了这些图表:
- 顶部核心指标卡:今日PV、今日UV、今日下单量、整体转化率。
- 左侧转化漏斗图:浏览→收藏→加购→购买的整体转化链路。
- 中间商品热销Top10柱状图,并列出未来可能购买用户预测名单。
- 右侧用户活跃时段热力图,横轴是小时,纵轴是星期几。
- 底部用地图展示不同城市的下单用户分布。
最有亮点的其实是“预测名单”和漏斗图的联动。漏斗图展示历史数据,预测名单回答未来趋势,前者是“已经发生了什么”,后者是“接下来可能发生什么”,正好把可视化和深度学习串起来,答辩时你可以顺着这条线讲,逻辑非常顺。
4.2 ECharts和Django模板集成
ECharts在Django模板里的用法,比很多人想象中简单。我在view里构造好图表需要的dict,传给模板,模板里用{{ chart_data|safe }}序列化到JavaScript变量,然后初始化ECharts实例。注意|safe过滤器一定要加,否则Django会转义引号和小括号,JSON被弄坏,图表怎么都不显示。
我通常会把每个图表的配置放到单独的JavaScript函数里,比如initFunnel(data)、initBar(data),这样即使某个图表数据没返回,页面其他部分也能正常渲染。另外,ECharts的data数据格式非常固定,接口返回的字段名一定要对清楚,比如漏斗图要用value和name字段,热力图要用[x, y, value]这样的三维数组。我调试时踩过最蠢的坑就是把列表当成对象传进去,控制台不报错但图表空白,后来对照官方示例才反应过来。
4.3 WebSocket实时推送与Redis可视化
做实时推送之前,先想清楚有没有必要。如果只需要“手动刷新页面能看新数据”,那完全不用上WebSocket。如果希望大屏像监控中心一样自动跳动,再考虑Django Channels。
我当时实现了一个简化版:后台用Redis作为消息队列,模拟程序不断往队列里写“用户发生新的购买行为”事件;Django Channels的Consumer订阅这个队列,当收到消息时通过WebSocket推送到前端页面,前端收到后重新请求一次热销榜接口,只更新柱状图部分。这个方案不复杂,但能很好展示你理解“推送机制”和“数据解耦”。调试时我习惯用Redis桌面可视化管理工具查看key数量和队列长度,确认消息确实生产出来了再去找前端的问题,效率会高很多。
5. 实操过程与关键代码片段
5.1 环境搭建与项目初始化
先说环境。我用的Python 3.10,Django 4.2,TensorFlow 2.13。建议先创建虚拟环境,不要一股脑全装进全局环境,否则后面依赖冲突会让人崩溃。依赖清单大致是这样:
pip install django djangorestframework channels pandas numpy scikit-learn tensorflow redis项目初始化用两条命令:
django-admin startproject taobao_analysis cd taobao_analysis python manage.py startapp behavior python manage.py startapp dashboardbehavior这个app放行为日志数据接入和特征处理,dashboard放可视化接口和大屏页面。接下来在settings.py里注册app,配置MySQL数据库,设置STATICFILES_DIRS指向放ECharts和自定义JS的目录。
项目结构最后会类似这样:
taobao_analysis/ ├── manage.py ├── taobao_analysis/ │ ├── settings.py │ └── urls.py ├── behavior/ │ ├── models.py │ ├── views.py │ └── train_features.py ├── dashboard/ │ ├── views.py │ ├── urls.py │ └── templates/ │ └── dashboard.html ├── ml_models/ │ └── best_model.keras └── static/ ├── echarts.min.js └── dashboard.js5.2 数据清洗和特征构建流程
拿到原始数据后,我一般先做三件事:过滤异常时间戳、映射行为类型、只保留最近15天数据。原始数据里的时间戳很多是秒级Unix时间戳,要转成datetime再提取“小时”和“星期几”特征。
数据清洗脚本用pandas即可:
import pandas as pd df = pd.read_csv('user_behavior.csv') df.columns = ['user_id', 'product_id', 'category_id', 'behavior_type', 'timestamp'] # 行为类型映射:pv=0, fav=1, cart=2, buy=3 behavior_map = {'pv': 0, 'fav': 1, 'cart': 2, 'buy': 3} df['behavior_code'] = df['behavior_type'].map(behavior_map) df['time'] = pd.to_datetime(df['timestamp'], unit='s') df['hour'] = df['time'].dt.hour df['weekday'] = df['time'].dt.weekday # 过滤过期数据,只保留最近15天 cutoff = df['time'].max() - pd.Timedelta(days=15) df = df[df['time'] >= cutoff] # 按用户抽样,保证训练集不超过10万用户 selected_users = df['user_id'].drop_duplicates().sample(n=100000, random_state=42) df = df[df['user_id'].isin(selected_users)]到这里,原始日志已经变成一张干净的行为流水表。再按用户聚合出统计特征和序列特征,最终生成训练集。训练集里每一行是一个用户,列是“统计特征列”和“行为序列列、标签列”,保存成csv。
5.3 模型训练与保存
训练脚本我会单独放一个train_lstm.py,和Django项目放在同一个仓库里但不用Django启动。这样调试模型时不用每次启动整个网站,更快。训练时用EarlyStopping和ModelCheckpoint,只保留验证集AUC最好的模型。
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint callbacks = [ EarlyStopping(monitor='val_auc', patience=3, mode='max', restore_best_weights=True), ModelCheckpoint('ml_models/best_model.keras', monitor='val_auc', save_best_only=True, mode='max') ] model.fit( [X_train_seq, X_train_feat], y_train, validation_data=([X_valid_seq, X_valid_feat], y_valid), epochs=15, batch_size=1024, callbacks=callbacks )一个比较实用的经验:batch_size根据显存调,没有GPU就用CPU跑,batch_size设小一点,512或1024都可以。整个15轮训练在普通笔记本电脑上大概十几分钟,完全可以接受。
5.4 Django接口与可视化页面实现
模型训练完成后,我写一个预测视图,放在behavior/views.py里:
from django.http import JsonResponse from .services import get_or_build_features, get_model def predict(request, user_id): feature = get_or_build_features(user_id) if feature is None: return JsonResponse({'error': 'user not found'}, status=404) seq = feature['sequence'] stat = feature['stat'] prob = get_model().predict([seq, stat])[0][0] return JsonResponse({'user_id': user_id, 'buy_probability': round(float(prob), 4)})核心是get_or_build_features函数,它必须和训练时的特征处理完全一致,差一步都会导致预测结果漂移。我踩过的一个坑是训练时把行为序列向左补齐到长度20,但预测接口忘补了,等于序列里全是0,模型预测毫无区分度。建议把特征构建逻辑抽成公共函数,训练和预测都调用同一个函数。
可视化页面我用Django模板实现。dashboard/views.py里写一个index视图,把图表需要的数据聚合成字典返回模板。模板中引入ECharts的js文件后,按官方文档初始化即可。
6. 常见问题与排查技巧实录
6.1 高频问题速查表
整理一份我在调试过程中遇到的高频问题,按“现象—原因—解法”列出,基本能覆盖大部分同学会踩的坑:
| 现象 | 原因 | 解决方法 |
|---|---|---|
| Django页面加载CSS/JS全部失效,控制台404 | 没有配置静态文件路径,或忘加{% load static %} | 在settings.py中设置STATICFILES_DIRS,模板中加入{% load static %},使用{% static 'xxx.css' %}引用 |
| ECharts图表不渲染,页面空白 | 传给option的变量不是合法JSON,Django转义了引号 | 在模板变量后加` |
| 模型预测AUC很高但线上效果差 | 数据切分方式有问题,随机切分导致数据泄露 | 改用按时间切分,不使用未来数据构造特征 |
| LSTM训练loss不降 | 学习率太高或特征未归一化 | 把统计特征做标准化,学习率降到0.001以内 |
| Django加载模型后内存暴涨 | 每次请求都调用load_model | 用lru_cache缓存模型对象,进程内只加载一次 |
| 预测接口返回结果全是同一个值 | 特征处理流程和训练流程不一致 | 检查序列补齐方向、缺失值填充方式,保证公共特征函数唯一 |
6.2 我自己的调试心得
最后分享几个不带在代码注释里的体会。第一个是关于Django执行查询和删除对象的习惯。很多人写Behavior.objects.filter(user_id=xxx).delete()之前不知道这个delete会返回一个元组,调试时以为删完就完事,结果后面统计数量还是老数据,后来才发现是缓存或没刷新。ORM删除、更新操作一定要看返回值,这是排查很多“奇怪行为”的第一步。
第二个心得是WebSocket如果实在调不出来,不要死磕。毕设核心是深度学习模型和可视化,实时推送属于锦上添花。我后来把推送功能砍成了轮询,页面照样能用,但我在文档里写了WebSocket的完整实现思路和代码片段,答辩时依然能证明我理解了这项技术。
第三个体会是珍惜自己的调试记录。做这个项目时我养成一个习惯:每修一个bug就写一段“现象+原因+处理方式”的笔记,后来整理成了一份问题排查文档,写进毕设文档里很加分。这些记录不只是给别人看的,也是自己复盘项目、准备答辩提问的最好素材。这个系统做完再回头看,最值钱的不是那几份源码,而是你在踩坑过程中建立起来的“数据-模型-系统”全链路直觉。