ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Django和协同过滤的得物App销售数据分析与推荐系统设计

基于Django和协同过滤的得物App销售数据分析与推荐系统设计 在电商赛道的毕设选题里“得物毒App商品销售数据”算得上一个既能蹭上热点、又不缺区分度的切入点。这个题目表面是“PythonDjango协同过滤可视化”的技术堆叠实际上它考验的是你能否把一套电商业务闭环拆清楚、把数据链路做完整。去年我帮工作室的学弟完整搭过这个方向的项目从数据采集清洗、指标体系建设、可视化大屏到协同过滤推荐引擎上线踩了不少坑也沉淀了一套可以直接复用的方案。这篇就顺着这个题目把整个项目的设计思路、核心代码、关键参数和常见问题全部梳理一遍不管你是拿来当毕设、课设还是想扩展成完整的实战项目都有参考价值。1. 项目整体设计与技术选型思路1.1 业务场景与核心需求拆解先把这个题目翻译成人话。得物是国内面向年轻人的潮流电商平台核心商品是球鞋、潮牌服饰、数码配件等。这个毕设要做的事情本质上就是两件第一把商品的销售数据变成看得见的图表第二根据用户的历史行为给用户推荐他可能想买的商品。拆开来看业务需求可以分成几个模块数据层需要有商品信息品类、品牌、价格、货号、销售流水订单金额、成交时间、购买数量、用户行为浏览、收藏、下单、评分。这是后续所有分析的原材料。分析层围绕销售数据构建指标体系比如GMV成交总额、销量趋势、品类占比、价格带分布、品牌热度、复购率等。这部分是可视化的数据支撑。展示层用可视化大屏或Dashboard把指标呈现出来常见形式是顶部核心KPI卡片加中部趋势折线图、右侧品类饼图、底部地域分布地图等。推荐层这是整个项目的算法亮点所在。需要构建用户-商品行为矩阵跑协同过滤算法计算相似度输出Top-N推荐列表并且要处理冷启动问题。从毕设评审的角度看最难的不是“画出图表”而是“把推荐算法讲清楚、调出合理效果”。协同过滤的价值在于它不依赖商品内容特征不需要图片、文字详情只需要用户行为数据就能给出推荐非常契合电商场景。1.2 技术栈选型Django、协同过滤与可视化组合的逻辑很多同学上来就问为什么选Django而不是Flask或SpringBoot我的回答是毕设最怕的不是功能实现不了而是工程量失控。Django自带Admin后台、ORM、模板引擎、认证体系这能帮你省下大量重复劳动把时间花在核心算法和业务逻辑上。具体选型方案如下层级技术选型选型理由后端框架Django Django REST Framework自带ORM和Admin快速构建API接口适合中小型系统数据库MySQL 8.0订单流水、用户行为都是结构化数据关系型数据库查询聚合能力成熟缓存Redis缓存热门商品列表、推荐结果降低数据库压力可视化ECharts前端 Pyecharts后端图表生成兜底ECharts生态完善、大屏效果成熟前端渲染灵活推荐算法基于用户的协同过滤UserCF 基于物品的协同过滤ItemCF电商场景经典算法不需要内容特征代码可实现性强数据处理Pandas NumPy SciPy清洗、聚合、相似度计算的标配组合部署Nginx uWSGI生产环境标准部署方案演示时用runserver也可关于可视化这里多说一句。Pyecharts确实可以直接在后端生成HTML图表文件集成方便但动态交互性偏弱图表数据更新后需要重新渲染。如果你想让大屏“活”起来比如切换日期范围、联动筛选品类建议前端用ECharts Ajax从接口拉取JSON数据这样体验好很多。我在项目里是两种方案同时保留首页大屏用ECharts报表导出页用Pyecharts生成静态图表各取所长。2. 数据准备与指标体系建设2.1 数据来源与核心表结构设计这个项目的数据来源一般有两类一类是从公开渠道爬取商品列表和销售信息另一类是构造模拟的订单流水。作为毕设我的建议是以模拟数据为骨架、以少量真实数据为点缀。爬取大量真实数据既不稳定又会增加法律风险完全用模拟数据又显得“不真实”评审老师一问数据来源就露怯。模拟数据也不是瞎编的要符合业务逻辑。比如得物的商品属性包括品牌Nike、Adidas、Air Jordan、Yeezy等、品类篮球鞋、跑步鞋、板鞋、服饰、价格区间500-5000元不等、发售时间。用户行为要符合分布规律比如大多数用户集中在浏览和收藏下单比例低一些。我用Faker库生成用户和订单数据再手动调整分布参数让数据看起来“像真的”。核心表结构设计MySQL用户表 user - id, username, age, gender, location, register_time 商品表 goods - id, name, brand, category, price, stock, listing_time 订单表 order - id, user_id, goods_id, quantity, amount, order_time, pay_status 用户行为表 behavior - id, user_id, goods_id, action_type(浏览/收藏/加购/购买), action_time, score需要特别注意的一点行为表是协同过滤算法的输入。实际项目里用户行为数据的数量级远大于订单数据要确保行为表中同一用户和同一商品之间有多条记录不能太稀疏否则后面相似度矩阵全空。2.2 核心销售指标体系GMV、复购率、价格带与动销率图表不会自己说话真正支撑页面表达的是指标体系。我最终确定的核心指标如下总GMV与订单量平台整体成交金额和单量是宏观盘子的判断依据。每日/每周销售趋势观察销售波动识别促销节点和周期性规律。品类销售占比按商品一级类目聚合销量和GMV用饼图/环形图展示。品牌热度排行按品牌聚合销量Top10用横向柱状图展示。价格带分布将商品价格划分为若干个区间如0-500、500-1000、1000-2000、2000计算各区间销量占比玫瑰图展示效果很好。复购率统计每个用户购买次数计算购买次数≥2的用户占比。这是电商平台非常看重的指标。SKU动销率有销量SKU数 / 总SKU数反映商品结构健康度。计算复购率我踩过一个坑先用分组聚合算出每个用户的订单数再对用户维度求分布这里SQL和ORM写法的分组层级很容易搞错。Django ORM里用annotate(Count(order))之后再用filter(order__count__gte2)做二次筛选需要注意annotate和filter的书写顺序。2.3 数据清洗与预处理要点模拟数据也有脏数据问题真实数据就更严重。我在预处理阶段总结了四个必做的清洗动作去重订单号做主键去重用户行为表中同一用户同一天对同一商品只保留得分最高的那一条记录。缺失值处理商品价格缺失的行直接删除地区缺失的可以归为“未知”订单时间为空的需要从支付时间推断。异常值过滤销量为负数、金额超过销售额上限的订单要剔掉。这里我用的是3σ原则做初筛即超过均值3倍标准差的记录单独标记再人工确认。时间字段统一把时间全部转成datetime类型并按天生成date_key字段方便后续按天聚合。预处理这块用Pandas做效率最高几十万条数据几秒就能跑完然后把清洗结果回写MySQL作为后续分析和推荐的统一数据源。3. 销售可视化分析模块实现3.1 可视化大屏的布局设计KPI卡片、趋势图与地理分布这一章是项目呈现的“门面”。评审老师第一眼看的就是首页大屏视觉效果好答辩就成功了一半。我采用的布局方案是典型的电商数据大屏结构顶部居中放项目标题两侧放核心KPI卡片总GMV、总订单量、用户数、平均客单价。左区域上部分放品类销量占比饼图下部分放品牌热度Top10横向柱状图。中区域核心位置放销售趋势折线图或面积图可切换按日/按周维度下方放价格带分布玫瑰图。右区域上部分放复购率指标卡和用户年龄分布柱状图下部分放地域销售分布地图这里用的是中国地图。底部滚动播放热销商品Top榜单表格。这里有个工程细节ECharts地图需要单独注册中国的GeoJSON数据而且如果离线部署地图文件一定要本地引用不要用CDN否则演示现场没网就会空白。ECharts 5以后地图数据不再默认打包需要从echarts/map/js/china.js这类路径手动引入很多人第一次搞都会卡住。3.2 Django后端接口设计与ORM聚合查询数据大屏不能直接读数据库要走API接口。我设计了四个核心接口/api/kpi/返回核心指标汇总用聚合查询一次性统计。/api/trend/?days30返回近N天销售趋势。/api/category/返回品类销售占比。/api/rank/?limit10返回品牌热度和热销商品列表。接口写法上有两个关键点一是能用ORM聚合就尽量别用Python循环二是不需要返回的字段坚决不查。下面这段是一个典型的KPI聚合查询用aggregate配合F表达式一次性完成多种统计from django.db.models import Sum, Count, Avg, F def get_kpi_data(request): # 订单表聚合GMV、订单量、客单价 order_stats Order.objects.filter(pay_status1).aggregate( total_gmvSum(F(quantity) * F(amount)), total_ordersCount(id), avg_amountAvg(F(quantity) * F(amount)), ) user_count User.objects.count() data { total_gmv: round(order_stats[total_gmv] or 0, 2), total_orders: order_stats[total_orders] or 0, avg_amount: round(order_stats[avg_amount] or 0, 2), user_count: user_count, } return JsonResponse({code: 0, data: data})注意F(quantity) * F(amount)这个写法它可以让数据库层完成乘法计算而不是把全部订单捞到Python内存里算这是性能差异很大的习惯。几十万条订单如果不用聚合页面基本秒崩。3.3 前端Ajax联动筛选与图表实时刷新大屏页面前端我用的是原生HTML ECharts Ajax没有额外引Vue因为毕设项目不需要把复杂度堆那么高。页面加载时先用fetch并行请求四个接口然后渲染图表。联动筛选的逻辑是日期范围选择器变化时重新请求/api/trend/同时刷新中区域图表其他图表保持不变。一个比较容易忽略的坑是异步请求的时序问题。如果用户快速切换了好几次日期范围上一次的请求结果可能晚于下一次返回导致图表显示错乱。解决方法是给请求加一个AbortController切换时先中断上一个请求或者用一个递增的requestId做标识只渲染最新一次的结果。图表刷新不能整页刷新否则会闪烁。ECharts提供了setOption的增量更新能力新数据和旧数据对比后会自动做动画过渡体验好很多。4. 协同过滤推荐系统实现4.1 UserCF与ItemCF的原理拆解与场景选择协同过滤是项目里最核心的算法部分我花了大量篇幅写代码和调参。先讲清楚原理这部分答辩时一定会被问到。**基于用户的协同过滤UserCF**的核心逻辑是如果你和某个用户的历史行为高度相似那么你喜欢的东西他也大概率喜欢。流程分三步建立用户-商品行为评分矩阵计算用户之间的相似度找到相似用户集合把他们喜欢而当前用户没买过的商品推荐出来。**基于物品的协同过滤ItemCF**的核心逻辑是商品A和商品B被同一批用户购买过它们就是相似的用户买了A就推荐B。流程也分三步建立商品共现矩阵哪些商品被同一用户买过计算商品相似度根据用户历史购买记录推荐相似商品。两种算法在电商场景的选择上我的经验是ItemCF更容易解释——“因为你买过AJ1所以我们推荐Dunk SB”这是电商平台主流做法UserCF适合用户规模较小、兴趣变化快的场景。在毕设里我选择双算法都实现推荐时按策略融合这样既能体现算法深度又能应对提问。4.2 相似度计算的三种方式与选型对比相似度计算是协同过滤的心脏我用表格把三种主流方式列出来方法公式思路优点缺点适用场景余弦相似度向量夹角余弦值计算简单不受数值尺度影响忽略了用户评分尺度差异评分矩阵稀疏时的默认选择修正余弦相似度减去用户平均分后再算余弦消除用户评分偏置计算量稍大评分数据存在用户口味偏差时皮尔逊相关系数中心化后的向量相关性考虑评分尺度差异结果更准行为稀疏时易失效数据较稠密时精度最高Jaccard相似度交集/并集只依赖交互有无计算极快忽略数量级信息只有0/1行为购买与否场景在实际代码里我直接用scipy.spatial.distance.cosine和numpy.corrcoef没有手写循环。用scipy.sparse.csr_matrix存评分矩阵因为电商场景下用户-商品矩阵极度稀疏购买记录占总格子的比例通常低于1%用稠密矩阵很容易内存爆炸。4.3 评分矩阵构建与Top-N推荐完整代码这是推荐模块的核心实现。评分矩阵的行为用户、列为商品值可以是0/1是否购买也可以是评分如果行为表中有显示评分字段。我在项目中同时保留了两种评分方式但最终跑推荐用的是基于“购买收藏”的加权评分购买记5分加购记3分收藏记2分浏览记1分。构建矩阵和计算用户相似度的核心代码import pandas as pd import numpy as np from scipy.sparse import csr_matrix from sklearn.metrics.pairwise import cosine_similarity def build_user_item_matrix(records): records: list of (user_id, goods_id, score) df pd.DataFrame(records, columns[user_id, goods_id, score]) # 生成矩阵缺失值填0 matrix df.pivot_table(indexuser_id, columnsgoods_id, valuesscore).fillna(0) # 转换成稀疏矩阵节省内存 sparse_matrix csr_matrix(matrix.values) return matrix.index, matrix.columns, sparse_matrix def user_cf_recommend(user_id, matrix_index, matrix_cols, sparse_matrix, top_k5, k_similar10): # 计算用户相似度矩阵 sim_matrix cosine_similarity(sparse_matrix) user_idx list(matrix_index).index(user_id) # 取相似度最高的 k_similar 个用户 similar_users np.argsort(-sim_matrix[user_idx])[1:k_similar1] # 候选商品相似用户买过但当前用户没买过的商品 current_user_items set(matrix_cols[sparse_matrix[user_idx].toarray()[0] 0]) scores {} for like_user_idx in similar_users: sim_score sim_matrix[user_idx][like_user_idx] items_of_like_user sparse_matrix[like_user_idx].toarray()[0] for goods_idx, val in enumerate(items_of_like_user): if val 0 and matrix_cols[goods_idx] not in current_user_items: scores[matrix_cols[goods_idx]] scores.get(matrix_cols[goods_idx], 0) sim_score * val ranked sorted(scores.items(), keylambda x: x[1], reverseTrue)[:top_k] return ranked这段代码里有几个细节值得展开。第一sim_matrix是稠密的二维矩阵用户数上了5万就会非常大所以我是在局部用户子集上计算的先通过粗筛缩小候选范围再精细算。第二argsort(-sim_matrix[user_idx])是为了取相似度最高的索引因为默认是升序排序。第三候选商品只用“相似用户行为中权重高的商品”并且过滤掉了当前用户已经买过的避免推荐重复。ItemCF的共现矩阵构建思路类似只是行列交换本质上都是矩阵乘法。这里再补充一句两个算法结果的融合方式。我在最终推荐列表里采用加权融合权重系数为0.6*ItemCF_score 0.4*UserCF_score这个比例是调出来的不是拍脑袋定的。4.4 冷启动、算法优化与评估指标冷启动是答辩时最容易被追问的点。新用户没有任何行为数据协同过滤算不出相似度这时候的兜底策略有两种一是给热门商品——统计全站销量Top50直接按热度推荐二是给同类目商品——基于人口统计信息年龄、性别、地区推荐对应类目下的畅销品。我在系统里做了规则判断如果用户行为记录少于3条就走热门/类目兜底否则走协同过滤。算法优化方面我做了三件事热门物品惩罚IUF Inverse User Frequency某件商品被越多用户买过它在相似度计算中的贡献就被压得越低这能避免推荐列表全是爆款、没有个性化。实现时在相似度求和阶段对热门商品乘一个小于1的系数。时间衰减因子用户一年前买过的东西和昨天买的东西权重应当不同。我在评分时乘了exp(-days_ago / 90)时间越久权重越低。similarity阈值过滤相似度低于0.3的用户不参与推荐这个阈值能过滤掉大量噪声。评估推荐结果我用的是离线划分数据集的方法把行为数据按时间排序前80%作为训练集后20%作为测试集。然后计算精确率、召回率、F1和覆盖率。精确率 推荐列表中真正被用户购买的商品数 / 推荐列表长度召回率 推荐列表中真正被用户购买的商品数 / 用户实际购买的商品总数覆盖率 被推荐到的商品数 / 全站商品总数衡量推荐系统的多样性实测下来在模拟数据集上Top-10推荐精确率能做到18%-25%左右覆盖率50%上下。真实数据可能低一些但毕设演示这个指标足够支撑内容了。5. Django工程结构与核心配置5.1 项目目录规划与App拆分工程结构如果一团乱麻后期扩展和答辩讲解都会很痛苦。我把项目拆成四个App各司其职hotsale_project/ ├── manage.py ├── config/ # 公共配置 │ └── settings.py ├── apps/ │ ├── users/ # 用户管理 │ ├── goods/ # 商品管理 │ ├── analysis/ # 数据分析和可视化接口 │ └── recommend/ # 协同过滤推荐 ├── static/ # 前端静态资源ECharts、CSS、JS ├── templates/ # HTML模板大屏页、后台页 └── scripts/ ├── generate_data.py # 模拟数据生成 ├── clean_data.py # 数据清洗 └── train_model.py # 离线训练推荐模型这个结构的好处是分析模块和推荐模块完全解耦推荐模块只需要从数据库和缓存里取数据不依赖可视化模块的具体实现。后期想把推荐算法换成深度学习模型只需要替换recommend内部逻辑前端和数据库完全不用动。5.2 数据库配置与Redis缓存策略Django的数据库配置和大部分Python项目的配置方式一致推荐在settings.py里用环境变量管理敏感信息不要硬编码账号密码。Redis在这个项目里承担了三个角色缓存推荐结果、缓存热门榜单、做简单限流。推荐结果缓存的关键是设置合理的过期时间我的策略是热门商品榜单缓存30分钟个性化推荐结果缓存10分钟因为个性化结果变化相对较慢10分钟足够。5.3 从本地到部署uWSGI与Nginx配置实战本地用python manage.py runserver开发没问题但演示或部署到服务器时一定要换uWSGI Nginx的组合。Nginx配置的关键是静态文件处理和反向代理server { listen 80; server_name your_domain; location /static/ { alias /path/to/hotsale_project/static/; } location / { include uwsgi_params; uwsgi_pass 127.0.0.1:8001; } }uWSGI启动命令uwsgi --http 127.0.0.1:8001 --module hotsale_project.wsgi --processes 4 --threads 2 --static-map /static/path/to/static这里有一项必须注意的细节Django的DEBUG模式在生产环境一定要关闭否则会把完整的堆栈信息暴露出来既危险又拖慢性能同时需要配置ALLOWED_HOSTS。如果不配置页面会直接报DisallowedHost错误。部署完后建议跑一遍python manage.py collectstatic把静态文件统一收集到指定目录再交给Nginx。6. 常见问题与排查技巧实录6.1 数据与数据库层问题的排查项目开发过程中我遇到了不少场景化的问题总结成速查表方便你复用问题现象可能原因解决方案中文乱码数据库字符集不是UTF8MB4建库时指定CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci或ALTER DATABASE修改聚合查询结果出现None表为空或聚合条件不匹配aggregate返回值用or 0兜底导入50万条数据很慢逐条INSERT改用bulk_create批量插入或使用LOAD DATA方式Django ORM查询N1问题多表查询没有用select_related/prefetch_related根据模型关系选择预取策略时间字段比较出问题时区设置USE_TZTrue且存储UTC时间在settings.py中配置TIME_ZONE Asia/Shanghai其中最容易忽视的是时区问题。Django默认开启UTC时区如果前端的图表展示的是“本地时间”展示出来的数据可能偏差8小时。我在做趋势图时踩过这个坑出现了“凌晨0点到8点销量为0”的诡异现象排查很久才发现是时区转换问题。6.2 推荐算法效果的常见瓶颈推荐模块的问题是最有技术含量的我把调试过程中遇到的典型问题整理出来矩阵稀疏导致的相似度空值当用户-商品矩阵极度稀疏时很多用户之间没有共同购买记录余弦相似度结果会全是0。解决思路是换成商品共现矩阵来计算物品相似度商品数量远小于用户数量稀疏度会显著降低或者直接用Jaccard相似度它只看有无交集对稀疏数据更友好。推荐列表都是爆款这是热门物品未被惩罚时会出现的典型现象。加上IUF惩罚因子后推荐列表的多样性明显提高。我实测调整IUF权重从0到0.5覆盖率从30%提升到了50%左右。离线评估指标太低一开始我的精确率只有8%排查后发现是评分矩阵构建方式不对——只用了购买行为浏览和收藏都丢弃了导致正样本太少。后来把浏览、收藏、加购、购买分别赋予不同权重后精确率翻了一倍。推荐结果与用户性别/年龄完全无关协同过滤只依赖行为没有用户画像信息。如果商品库里某个类目的行为记录太少推荐结果自然单调。这可以通过增加“基于人口统计的规则”来补充在推荐列表尾部混入按年龄和性别匹配的类目热门商品实测体验会好不少。6.3 可视化页面的性能与兼容性坑可视化模块的问题是“看起来小、实际很烦”的类型ECharts地图空白多半是GeoJSON没有加载成功检查浏览器Network面板确认JS文件是否404离线环境务必本地引用。大屏加载慢首屏一次性请求过多图表接口可以用并行请求骨架屏优化或者对销售明细类数据做后端分页/聚合别把几十万条明细一股脑丢给前端。ECharts容器宽度为0导致图表不显示常见于Tab切换或初始化时容器隐藏需要在容器显示后再调用echarts.init或调用resize方法重绘。数据量过大渲染卡顿可以开启ECharts的sampling采样功能折线图降采样后视觉上几乎无感知但帧率大幅提升。7. 项目扩展方向从大数据到大模型agent的衔接如果你不满足于“基础毕设”想把项目拔高一个档次标题里提到的大模型和agent也能在这个项目上找到自然的落点。第一个方向是推荐结果解释生成。协同过滤只能给出“推荐什么”但很难回答“为什么推荐”。大模型可以把推荐理由变成一句话比如“因为你常浏览Jordan Brand的球鞋且和你偏好相似的剁手党也入手了AJ1低帮版所以为你推荐这款”。在推荐接口里加入解释字段前端展示出来答辩时会让老师眼前一亮。第二个方向是策略型agent动态调度。可以设计一个简单的agent它监控当前系统的各项指标如实时销量、推荐覆盖率、用户反馈点击率当发现覆盖率过低时自动把融合权重从默认的ItemCF主导切换为均衡模式当发现爆款热度失衡时自动提高IUF惩罚系数。这种“根据业务状态动态调整算法参数”的设计比手动调参要高级得多。第三个方向是数据链路的大数据迁移。当数据量增长到千万级别Pandas单机跑不动的时候可以迁移到Spark或Flink做离线计算Django只承担展示和API层。这块涉及的技术栈更重好处是项目可以称得上“大数据”。不过要提醒一点扩展方向要量力而行基础的主线功能可视化协同过滤一定要稳扩展功能是锦上添花。我见过很多同学上来就搞大模型结果主链路的可视化还没跑通最后两边都没做好。结尾这个项目我从数据生成、清洗、指标体系搭建到可视化大屏、协同过滤算法、Django接口再到Nginx部署完整跑了好几遍。我个人在实际操作中的体会是这个项目的核心价值不在于“技术有多新”而在于它把一套电商数据分析与推荐的真实工作流完整走了一遍。答辩时老师最关注的通常不是某个算法有多精妙而是你是否理解每一个环节为什么这么做以及遇到问题时能否给出排查思路。最后再分享一个小技巧在写推荐模块的时候一定不要把算法逻辑硬编码进视图函数里。单独封装成服务类通过配置文件控制算法参数相似度阈值、K值、融合权重这样调参就不需要反复改动代码只需改配置文件非常省心。如果你打算照这个方向做毕设建议先跑通最小闭环数据清洗 → 一个KPI接口 → 一张趋势图 → 一个最简单的UserCF推荐 → 写文档。剩下的模块在这个闭环上逐步扩展就行。这套思路能帮你避免“前期拖太久、后期赶工”的常见困境。
返回列表