
简介本资源是一套面向计算机专业本科生的毕业设计实战项目基于Django框架与深度学习技术构建淘宝用户购物行为可视化与预测系统解决电商场景下用户行为分析、趋势预判与数据驱动决策等实际问题适用于课程设计、毕设开发及AIWeb工程能力提升。压缩包共174个文件含30个核心Python后端逻辑与模型代码、26个JavaScript前端交互脚本、21个Vue组件、41张界面截图与25张图表PNG、1个MP4演示视频以及bat批处理脚本如安装.bat、运行.bat和SQL数据库初始化文件整体34.71MB结构清晰开箱即用。已有56人学习下载资源提供完整可运行源码、全流程演示视频、前后端分离架构实现及MySQL数据管理方案涵盖数据清洗、ECharts可视化、TensorFlow/PyTorch模型训练与预测模块便于快速部署、二次开发与算法调优。1. 这不是又一个“用户画像”PPT它用真实淘宝行为数据跑通了从Django后端到LSTMAttention行为预测的全链路你见过多少毕业设计标题写着“用户行为分析”打开是几张Excel截图百度ECharts模板图一段“用户越来越注重性价比”的结论这个资源不是。它基于真实爬取的淘宝商品页、用户评论、店铺信息非敏感字段不含手机号/身份证/支付记录构建了包含6类用户行为事件浏览、加购、收藏、下单、付款、评价的时间序列数据集在Django框架内封装了完整的数据清洗管道自动处理缺失时间戳、去重ID、行为归一化并用PyTorch实现了一个带位置编码与多头注意力机制的LSTM模型——不是调torch.nn.LSTM就完事而是手动拼接了nn.Linear层做特征投影、用nn.MultiheadAttention替代传统attention gate、最后接sigmoid输出未来24小时购买概率。它不教你怎么写论文但能让你答辩时被老师当场追问“你这个attention权重可视化是怎么做的”——因为源码里真有attention_weights.npy导出逻辑和对应的Django视图路由。适合正在赶毕设 deadline 的计算机/信管/电商专业学生也适合想快速验证“行为序列建模Web展示”闭环的一线开发。2. 数据层从原始淘宝页面结构到可训练时序数据集的三步清洗法2.1 爬虫模块设计只抓关键字段规避反爬黑盒项目未提供爬虫源码因涉及目标网站策略变动风险但附带了清洗脚本data_cleaning/parse_taobao_raw.py和一份已脱敏的示例数据集data/sample_taobao_behavior.json含127个用户、3892条行为记录。该数据集结构如下{ user_id: u_88234, behavior_seq: [ {timestamp: 2023-05-12T08:23:17, item_id: i_9912, action: view, category: mobile_phone}, {timestamp: 2023-05-12T09:15:02, item_id: i_9912, action: cart, category: mobile_phone}, {timestamp: 2023-05-13T14:44:33, item_id: i_2045, action: buy, category: charger} ] }提示behavior_seq按时间升序排列action字段仅保留view/cart/collect/buy/pay/comment六种其他如share、follow_shop等被过滤。这是为后续LSTM输入对齐做准备——所有序列必须用相同动作空间编码。2.2 时间窗口切片为什么用14天滑动窗口而非固定周期模型输入要求固定长度序列。项目采用14天滑动窗口 行为填充策略而非简单截取最后N条记录。原因有三业务合理性淘宝用户决策周期集中在7–14天促销预热→比价→下单过短如3天丢失长期兴趣信号过长如30天引入噪声数据对齐性不同用户行为密度差异极大活跃用户日均20次沉默用户周均1次固定条数会导致部分样本全是PAD预测一致性预测目标为“未来24小时内是否购买”若用固定条数切片窗口起始时间无法对齐导致label生成错位。核心代码在data_preprocess/sequence_builder.pydef build_sequences(raw_data, window_days14, pred_horizon1): raw_data: list of dict, each with user_id and behavior_seq window_days: 滑动窗口长度天 pred_horizon: 预测目标时间跨度小时此处固定为24 sequences [] for user in raw_data: seq sorted(user[behavior_seq], keylambda x: x[timestamp]) # 转为datetime对象便于计算 dt_seq [datetime.fromisoformat(x[timestamp]) for x in seq] # 从最早行为开始每14天切一个窗口 start_idx 0 while start_idx len(dt_seq): window_end dt_seq[start_idx] timedelta(dayswindow_days) # 取窗口内所有行为 window_behaviors [] for i, dt in enumerate(dt_seq[start_idx:]): if dt window_end: window_behaviors.append(seq[start_idx i]) else: break # 构建X窗口内行为和y窗口结束后24h内是否有buy if len(window_behaviors) 3: # 至少3条行为才构成有效样本 X encode_behavior_sequence(window_behaviors) # 返回 (seq_len, feature_dim) y 1 if has_buy_in_next_hours(seq, window_end, pred_horizon) else 0 sequences.append({X: X, y: y, user_id: user[user_id]}) start_idx 1 # 滑动步长为1天非1行为 return sequences参数说明window_days14硬编码值已在settings.py中定义为常量BEHAVIOR_WINDOW_DAYS修改需同步更新模型输入shapepred_horizon1单位为小时实际预测目标是“窗口结束时刻起24小时内是否发生buy行为”代码中通过has_buy_in_next_hours()函数遍历后续行为判断start_idx 1滑动步长为1天非1行为保证时间连续性避免漏掉跨窗口行为模式。2.3 特征工程6维动作向量 类别嵌入 时间差分编码输入特征不是简单one-hot动作类型。项目采用三级编码编码层级字段维度说明基础动作action6维[view, cart, collect, buy, pay, comment]二值向量品类嵌入category128维使用预训练的Word2Vec在models/embeddings/category_w2v.model中映射为稠密向量覆盖手机、服饰、食品等18个大类时间特征time_diff3维相对于窗口起始时间的小时差归一化到[0,1]、星期几one-hot, 7维、是否节假日0/1最终单条行为向量维度 6 128 3 137维。encode_behavior_sequence()函数返回(seq_len, 137)张量直接喂给LSTM。注意time_diff的“小时差”不是绝对时间戳而是当前行为时间 - 窗口起始时间的小时数再除以window_days * 24归一化——这使得不同窗口的同一相对位置具有可比性。3. 模型层LSTMAttention不是噱头是解决长程依赖的刚需3.1 为什么不用纯Transformer——显存与序列长度的现实妥协项目选择LSTM主干Attention头而非端到端Transformer原因直白训练数据中平均序列长度为23.7标准差±15.2最长序列达127条行为若用标准Transformerd_model128,nhead4单样本内存占用约127^2 × 128 ≈ 2.1MB批量大小设为32时GPU显存峰值超65GB实测V100 32G OOMLSTM虽存在梯度消失但配合nn.utils.rnn.pack_padded_sequence可跳过PAD位置计算实测同等batch下显存降低62%训练速度提升2.3倍。模型结构定义在models/lstm_attention.pyclass BehaviorLSTMAttention(nn.Module): def __init__(self, input_dim137, hidden_dim128, num_layers2, num_heads4, dropout0.3): super().__init__() self.lstm nn.LSTM( input_sizeinput_dim, hidden_sizehidden_dim, num_layersnum_layers, batch_firstTrue, dropoutdropout if num_layers 1 else 0, bidirectionalFalse ) self.attention nn.MultiheadAttention( embed_dimhidden_dim, num_headsnum_heads, dropoutdropout, batch_firstTrue ) self.classifier nn.Sequential( nn.Linear(hidden_dim, 64), nn.ReLU(), nn.Dropout(dropout), nn.Linear(64, 1) ) def forward(self, x, lengths): # x: (batch, seq_len, input_dim), lengths: (batch,) 表示各序列真实长度 packed_x nn.utils.rnn.pack_padded_sequence(x, lengths, batch_firstTrue, enforce_sortedFalse) lstm_out, _ self.lstm(packed_x) unpacked_out, _ nn.utils.rnn.pad_packed_sequence(lstm_out, batch_firstTrue) # (batch, seq_len, hidden_dim) # Attention: querykeyvalueunpacked_out attn_out, _ self.attention(unpacked_out, unpacked_out, unpacked_out) # (batch, seq_len, hidden_dim) # 取最后一个非PAD位置的输出即序列结尾状态 last_idx torch.tensor([l-1 for l in lengths], dtypetorch.long) final_state attn_out[torch.arange(len(lengths)), last_idx] # (batch, hidden_dim) return torch.sigmoid(self.classifier(final_state)).squeeze(-1)参数说明input_dim137严格对应2.3节特征维度不可更改hidden_dim128LSTM隐藏层大小也是Attention的embed_dim影响显存和表达能力num_layers2双层LSTM第二层输入为第一层输出增强非线性num_heads4MultiheadAttention头数必须整除hidden_dim128÷432lengths参数由data_preprocess/sequence_builder.py中的get_lengths()函数生成用于pack/unpack缺少此参数将导致PAD位置参与计算预测结果全为0.5。3.2 Attention权重可视化不只是为了答辩PPT模型训练完成后train.py会自动生成attention_weights/目录内含每个验证样本的.npy文件如u_88234_20230512.npy形状为(seq_len, seq_len)。项目配套Django视图/visualize/attention/user_id/date/将其渲染为热力图。关键逻辑在views.pydef attention_heatmap(request, user_id, date_str): # 加载对应npy文件 npy_path os.path.join(settings.BASE_DIR, attention_weights, f{user_id}_{date_str}.npy) if not os.path.exists(npy_path): raise Http404(Attention weights not found) weights np.load(npy_path) # shape: (seq_len, seq_len) # 只取上三角自注意力对称下三角冗余 mask np.triu(np.ones_like(weights, dtypebool), k1) weights_masked np.where(mask, weights, np.nan) # 生成HTML表格简化版实际用Plotly html_table table border1trth行为索引/th for i in range(weights.shape[0]): html_table fth{i}/th html_table /tr for i in range(weights.shape[0]): html_table ftrth{i}/th for j in range(weights.shape[1]): val weights_masked[i][j] bg_color frgb({int(255*(1-val))}, {int(255*val)}, 128) if not np.isnan(val) else #f0f0f0 html_table ftd stylebackground-color:{bg_color};text-align:center;{val:.2f}/td html_table /tr html_table /table return HttpResponse(html_table)注意此功能需在训练时设置--save_attention True见train.py第127行否则不会生成.npy文件。且仅对验证集样本保存训练集因数量过大默认关闭。3.3 避坑LSTMAttention训练中五个血泪经验现象1验证loss震荡剧烈auc在0.5~0.7间反复横跳→ 原因未对输入特征做标准化。137维向量中time_diff范围[0,1]而category嵌入向量L2范数均值为3.2导致LSTM门控单元梯度失衡。→ 解决在data_preprocess/sequence_builder.py中加入StandardScaler对time_diff三列单独标准化因分布偏斜其余134维用全局均值方差归一化。现象2模型预测全为0.5sigmoid输出恒定→ 原因final_state取索引错误。代码中last_idx torch.tensor([l-1 for l in lengths])但若某序列lengths[i]0空序列则l-1-1取到倒数第一个元素造成张量错位。→ 解决增加校验last_idx torch.clamp(last_idx, min0)并在数据清洗阶段过滤len(behavior_seq)3的用户。现象3Attention热力图全黑或全白→ 原因weights矩阵未经过softmax归一化。nn.MultiheadAttention输出的是raw scores需手动F.softmax(weights, dim-1)。→ 解决在forward()末尾添加attn_weights F.softmax(self.attention(...)[1], dim-1)并保存。现象4Django启动时报ModuleNotFoundError: No module named torch→ 原因Django运行环境与PyTorch训练环境分离。项目要求requirements.txt中torch版本为1.12.1cu113CUDA 11.3但服务器若无GPU需改用cpuonly版本。→ 解决执行pip install torch1.12.1cpu torchvision0.13.1cpu torchaudio0.12.1 --extra-index-url https://download.pytorch.org/whl/cpu。现象5预测接口响应超时30sNginx报504→ 原因单次预测加载整个模型217MB embedding字典89MB到内存Django worker进程阻塞。→ 解决在apps/predict/apps.py中实现模型懒加载——首次请求时初始化model和embedding_dict为Nonepredict_view中检查为空则加载后续请求复用。4. Django服务层把深度学习模型变成可调试的Web API4.1 路由设计RESTful风格与前端解耦项目采用Django REST FrameworkDRF构建API而非Django原生View。核心路由定义在predict/urls.pyfrom django.urls import path, include from rest_framework.routers import DefaultRouter from . import views router DefaultRouter() router.register(rusers, views.UserViewSet, basenameuser) router.register(rpredictions, views.PredictionViewSet, basenameprediction) urlpatterns [ path(api/, include(router.urls)), path(api/visualize/attention/str:user_id/str:date_str/, views.attention_heatmap, nameattention_heatmap), path(api/visualize/timeline/str:user_id/, views.user_timeline, nameuser_timeline), ]关键点UserViewSet提供用户列表、详情、行为序列查询GET/api/users/PredictionViewSet处理预测请求POST/api/predictions/接收{user_id: u_88234, as_of_date: 2023-05-12}返回{probability: 0.872, risk_level: high}attention_heatmap和user_timeline是独立函数视图不走DRF便于前端直接嵌入iframe。4.2 模型加载与缓存避免每次请求都反序列化views.py中PredictionViewSet.predict()方法使用单例模式管理模型# models/predictor.py class ModelSingleton: _instance None model None embedding_dict None def __new__(cls): if cls._instance is None: cls._instance super().__new__(cls) return cls._instance def load_model(self): if self.model is None: self.model BehaviorLSTMAttention() state_dict torch.load(models/best_model.pth, map_locationcpu) self.model.load_state_dict(state_dict) self.model.eval() # 关键否则BatchNorm层报错 if self.embedding_dict is None: with open(models/embeddings/category_w2v.model, rb) as f: self.embedding_dict pickle.load(f) # views.py class PredictionViewSet(viewsets.ViewSet): def predict(self, request): predictor ModelSingleton() predictor.load_model() # 首次调用加载后续复用 user_id request.data.get(user_id) as_of_date request.data.get(as_of_date) # ... 数据获取与预处理 with torch.no_grad(): # 关键禁用梯度节省显存 prob predictor.model(X, lengths).item() return Response({probability: round(prob, 3), risk_level: self._risk_level(prob)})提示model.eval()和torch.no_grad()必须同时存在。前者关闭Dropout/BatchNorm训练模式后者防止计算图构建——缺少任一都会导致显存泄漏5次请求后OOM。4.3 用户行为时间线可视化ECharts不是万金油要适配行为密度user_timeline视图GET/api/visualize/timeline/u_88234/返回JSON格式时间线数据前端用ECharts渲染。但淘宝用户行为存在脉冲式爆发如大促日单日200次浏览直接按时间轴绘制会挤成黑线。项目采用动态聚合策略当日行为数 ≤ 5逐条显示图标文字6–50条按小时聚合柱状图高度该小时行为数50条按日期聚合折线图显示日行为总量并标注峰值时段如“5月12日 20:00–21:00浏览加购 47次”。后端聚合逻辑在views.pydef user_timeline(request, user_id): behaviors get_user_behaviors(user_id) # 从数据库或缓存获取 # 按小时聚合 hourly_counts defaultdict(int) for b in behaviors: hour_key datetime.fromisoformat(b[timestamp]).strftime(%Y-%m-%d %H:00) hourly_counts[hour_key] 1 # 判断聚合粒度 total len(behaviors) if total 5: data [{time: b[timestamp], action: b[action], item: b[item_id]} for b in behaviors] chart_type list elif total 50: data [{time: k, count: v} for k, v in sorted(hourly_counts.items())] chart_type bar else: daily_counts defaultdict(int) for b in behaviors: day_key datetime.fromisoformat(b[timestamp]).strftime(%Y-%m-%d) daily_counts[day_key] 1 data [{date: k, count: v} for k, v in sorted(daily_counts.items())] # 找峰值时段 peak_hour max(hourly_counts.items(), keylambda x: x[1]) data.append({peak: f{peak_hour[0]}: {peak_hour[1]}次}) chart_type line return JsonResponse({chart_type: chart_type, data: data})5. 部署与调试从本地runserver到生产环境的四道坎5.1 数据库迁移SQLite够毕业设计但得防schema冲突项目默认使用SQLitesettings.py中DATABASES[default][ENGINE] django.db.backends.sqlite3适合本地开发。但需注意python manage.py makemigrations会生成predict/migrations/0001_initial.py其中BehaviorEvent模型的timestamp字段定义为models.DateTimeField()若你曾手动修改过该字段如改为models.CharField再次makemigrations会创建新迁移文件如0002_alter_behavior_timestamp.py导致migrate时报错django.db.migrations.exceptions.InconsistentMigrationHistory正确做法删除predict/migrations/下除__init__.py外所有文件执行python manage.py makemigrations --empty predict创建空迁移再手动编辑该文件在operations中写入migrations.AlterField(...)修改语句。5.2 静态文件收集Django的collectstatic不是摆设演示视频和前端资源放在static/目录但Django生产模式DEBUGFalse下不会自动提供静态文件。必须设置STATIC_ROOT os.path.join(BASE_DIR, staticfiles)执行python manage.py collectstatic --noinput将所有static/内容复制到staticfiles/Nginx配置中添加location /static/ { alias /path/to/staticfiles/; }。否则访问/static/css/app.css返回404页面样式全崩。5.3 Gunicorn配置worker数不是越多越好项目提供gunicorn.conf.py关键参数workers 2 # CPU核心数×2但本项目I/O密集2足够 worker_class sync # 不用gevent因PyTorch多线程与gevent不兼容 timeout 120 # 预测接口可能耗时需延长 keepalive 5 max_requests 1000若设workers4在4核CPU上看似合理但LSTM预测本身是CPU密集型多worker会争抢CPU缓存实测QPS反而下降18%。血泪教训先压测再调参。5.4 日志排查当预测返回500看哪三行日志Django日志配置在settings.py的LOGGING字典中关键路径logs/django.logDjango框架级错误如URL路由失败logs/predict.log预测模块专属日志记录每次请求的user_id、as_of_date、耗时、异常堆栈logs/model_load.log模型加载日志记录load_model()调用时间及成功/失败。当预测接口返回500第一反应不是看浏览器控制台而是查logs/predict.log末尾三行是否有FileNotFoundError: [Errno 2] No such file or directory: models/best_model.pth→ 检查模型文件路径是否有RuntimeError: Expected all tensors to be on the same device→ 模型在GPU加载但torch.device(cpu)未指定是否有KeyError: u_99999→ 用户ID不存在于数据集中需检查get_user_behaviors()函数是否正确fallback。提示logs/目录需在部署前手动创建否则Django无法写入日志错误将静默丢失。6. 答辩现场技巧如何用3分钟讲清技术深度避开“调包侠”质疑6.1 预测结果解释不要只说“准确率87%”要说清“哪些用户容易误判”答辩时老师必问“你的模型在什么情况下会失效” 项目源码中analysis/error_analysis.py已内置分析脚本。运行它会生成reports/error_summary.csv关键字段user_typeerror_ratecommon_pattern示例用户新注册用户7天42.3%行为序列过短5条LSTM无法捕获模式u_new_20230510高频沉默用户日均浏览50但0购买38.1%Attention权重分散无显著聚焦点u_silent_88234跨品类用户14天内行为覆盖≥5个一级类目31.7%品类嵌入向量距离过大相似度计算失真u_diverse_11223答辩话术“老师我们的模型在整体测试集上AUC是0.872但更关键的是我们定位了三类高误差群体。比如新用户由于行为稀疏模型倾向于保守预测‘不购买’这时我们会主动触发规则引擎——如果该用户最近3小时搜索了‘iPhone 14’且点击了3个同款商品就强制覆盖为‘高概率’。这部分逻辑在predict/views.py的_hybrid_predict()函数中它实现了模型规则的双路径决策。”6.2 可视化大屏用真实交互证明不是PPT动画演示视频中/dashboard/页面包含三个核心组件用户行为热力图X轴为小时0–23Y轴为星期Mon–Sun颜色深浅表示该时段行为密度品类转化漏斗浏览 → 加购 → 下单 → 付款四步转化率支持按用户群筛选如“25–30岁女性”预测TOP10榜单实时滚动显示未来24小时最可能下单的10个用户点击任一用户进入其/visualize/timeline/详情页。关键细节热力图数据非静态而是每5分钟调用/api/predictions/latest/获取最新预测结果前端用setInterval轮询。这证明系统具备实时性不是离线跑批。6.3 源码可验证性答辩时当场打开IDE演示一个“小改动”老师若质疑“你真懂这个Attention吗”立刻打开models/lstm_attention.py找到forward()函数中Attention调用行attn_out, attn_weights self.attention(unpacked_out, unpacked_out, unpacked_out)然后说“老师我来验证一下Attention是否真的在工作。我把这一行改成attn_out, attn_weights unpacked_out, None也就是绕过Attention只用LSTM输出。重新训练后AUC从0.872降到0.791下降8.1个百分点。这说明Attention确实贡献了关键的长程依赖建模能力——它让模型能发现‘用户在5月10日浏览手机5月12日加购充电器5月13日下单’这种跨品类关联。”这个操作5分钟内可完成无需重启服务用python train.py --epochs 1 --model_path test_no_attn.pth即可验证。从那以后我每次答辩前都强制走一遍这个“绕过Attention”的对比实验哪怕只跑1个epoch。它让我在被问到模型原理时不是背概念而是有代码、有数字、有对比。希望帮到你。本文还有配套的精品资源点击获取