尧图精选

基于Python的服饰推荐系统实战:混合推荐与特征工程详解

🕒 发布时间:2026/10/1 7:11:54 📁 来源:尧图网络
简介一份基于 Python 的服饰推荐系统完整源码包适合用于毕业设计、课程设计与项目开发资源按前端应用、服务端、脚本和图像数据集四大目录组织包含从数据处理、推荐算法到页面展示的完整链路方便学生或开发者直接运行体验并二次拓展。压缩包内共 2000 个文件以 JPG 服装图像数据集为主体1863 张配合 CSV、JSON、XML 标签与配置数据以及 Vue、JS 前端页面和 Python 后端脚本整体大小约 223.8MB目前已有 79 人学习使用。项目文档为 Markdown 格式对目录结构、核心代码和运行方式进行了说明scripts 目录提供批量处理脚本images 中整理好的服装图片可直接用于模型训练或推荐测试。相比零散示例这份源码包提供了从数据到推荐的完整业务闭环适合需要快速搭建项目原型或理解推荐系统工程化实现的读者。1. 服饰推荐系统是个“毕业设计级”的坑算法太简单显得水工程太复杂则写不完以Python实现服饰推荐系统并配上源码和项目文档是本科毕设、课程设计里非常典型的一类任务。它看起来是“推荐算法”的活实际上你交上去的东西要同时扛住两把尺子导师会问算法为什么这么选答辩评委则关心系统能不能跑、数据哪来的、页面像不像样。很多同学卡在“协同过滤写完了但结果毫无解释力”或者“算法没问题但Web界面搭完推荐结果却没法看”。我给你的结论是把精力重点放在特征工程、用户行为数据自洽和可解释的推荐输出上算法用经典方法完全够用。适合人群是计算机、电商、信管类的本科生以及想在短期项目中补一个完整工程链路的Python学习者。下面从选型开始一步一步把这个系统从零搭到能答辩。2. 先把推荐算法选型定住协同过滤还是基于内容别一上来就写代码2.1 为什么毕业设计级的服饰推荐系统首选混合推荐服饰推荐和电影推荐看起来都是“给用户推TopN”但数据性质差别很大。影视数据天然有显式评分1到5星而服饰场景下绝大多数用户是不会打分的最多有点击、收藏、加购这些隐式反馈就算你拿到电商公开数据集评分也极度稀疏。另一个麻烦是服饰有强烈的属性特征品类、颜色、风格、价格带、适合季节这些对人的购买决策影响比“评分均值”更大。如果一个用户购买过黑色修身风衣你拿“喜欢风衣的人还喜欢”做协同过滤可能推给他黑色羽绒服但基于内容的方案能保证“黑色、修身、通勤”这些属性不出错。所以我一般建议毕设里用混合推荐先用基于内容的方法生成候选集保证推荐结果和用户历史行为在品类、风格上可解释再用协同过滤在候选集里做二次排序把“和你相似的用户还买了什么”混进去。这种结构写进论文里也很好讲故事——你不是抄了一个现成算法而是针对服饰场景做了方案设计。而且混合推荐在代码上是三个独立模块先后顺序清晰答辩时能一步步演示。2.2 用Python跑通最小的协同过滤评分矩阵与相似度计算先看协同过滤最基础的UserCF实现。这里我故意不引第三方推荐框架只用pandas和numpy目的是让你完全掌握计算过程后续换数据集、调参数都心里有底。import pandas as pd import numpy as np # 模拟5个用户对4件服饰的评分0表示没有行为 data { 用户: [U1, U2, U3, U4, U5], 黑色风衣: [5, 4, 0, 3, 0], 白色T恤: [3, 0, 4, 5, 2], 直筒牛仔裤: [0, 3, 5, 0, 4], 针织连衣裙: [4, 0, 0, 2, 5] } df pd.DataFrame(data).set_index(用户) print(df) # 计算用户与用户之间的余弦相似度 def cosine_sim(a, b): common (a 0) (b 0) if common.sum() 0: return 0.0 vec_a a[common].values vec_b b[common].values return np.dot(vec_a, vec_b) / (np.linalg.norm(vec_a) * np.linalg.norm(vec_b) 1e-9) # 以U1为例找到最相似的用户 target U1 scores {} for user in df.index: if user ! target: scores[user] cosine_sim(df.loc[target], df.loc[user]) similar_users sorted(scores.items(), keylambda x: x[1], reverseTrue) print(与U1最相似的用户:, similar_users[:2])这段代码的核心在于“只在共同评分的商品上算相似度”。很多初学实现直接对整行向量做余弦结果两个只共同买过一件衣服的用户相似度被大量零值拉高推荐就乱了。参数里我加了1e-9避免分母为0common.sum()过滤掉没有共同行为的用户对。拿到相似用户后预测U1对某件未买商品的评分就是对这些相似用户的评分按相似度加权平均这个步骤留给你自己补全——写论文时这是很好的“算法改进点”讲述素材。2.3 基于内容的推荐标签向量化与余弦相似度协同过滤在用户行为充足时表现好但新用户和新品没有行为时直接失效。基于内容的方法没有这个问题只要商品存在属性标签就能立即和新用户的注册偏好对齐。from sklearn.feature_extraction.text import CountVectorizer from sklearn.metrics.pairwise import cosine_similarity # 商品ID和它的“属性文本” items pd.DataFrame({ item_id: [A001, A002, A003, A004], tags: [ 黑色 风衣 修身 通勤 春秋, 白色 T恤 宽松 休闲 夏季, 蓝色 牛仔裤 直筒 休闲 春秋, 黑色 连衣裙 针织 修身 冬季 ] }) vectorizer CountVectorizer(token_patternr(?u)\b\w\b) tag_matrix vectorizer.fit_transform(items[tags]) sim_matrix cosine_similarity(tag_matrix) # 展示A001与其它商品的相似度 idx items.index[items[item_id] A001][0] sims list(enumerate(sim_matrix[idx])) for j, s in sims: if j ! idx: print(items.iloc[j][item_id], round(s, 3))这里CountVectorizer把每个标签当独立词one-hot后做余弦相似度。注意token_pattern这个参数如果不指定默认会把“黑色”和“风衣”拆成两个词没问题但如果你标签里带中文并在某些版本下默认分词不生效就会出现长度为0的报错。参数上我建议给min_df1、max_features500服饰标签一般几十个词不用限制太死。使用基于内容的方法推荐结果可以直接解释为“因为你的历史偏好包含黑色、修身、通勤所以给你推A001”。这一句话在答辩现场比“系统用了黑匣子模型”有说服力得多。下一章我们把这两块真正拼到服饰数据上。3. 把推荐做成“能穿的样子”服饰特征工程与TopN推荐落地3.1 服饰属性怎么设计品类、颜色、风格、价格带的编码方案推荐系统的上限往往由特征工程决定。服饰推荐最忌讳把商品ID当成唯一特征建模时要拆成四层属性基础属性品类、性别、季节、外观属性颜色、风格、版型、价格属性价格带、行为属性热度、点击率。我常用的结构是这样一张商品表字段名示例类型说明item_idA001str商品唯一IDcategory风衣str一级品类color黑色str主色style通勤str风格fit修身str版型season春秋str适用季节price_band中高str100-300元为中高hot_score0.87float归一化热度编码时不要一股脑做OneHot。比如颜色可以多选风格可以多个就把它们拼成空格分隔的标签文本交给CountVectorizer做词袋价格带则单独做序数编码因为“低中高”是有顺序语义的。你要是用不好二值化直接pd.cut把价格切成低、中低、中高、高四个档位也行。关键是保证训练和推荐时编码一致。3.2 没有真实用户日志时怎么造一份能自洽的行为数据课程设计通常没有真实的电商日志。常见做法是写一个带随机种子、但规则明确的数据生成脚本而不是把评分数组手写在代码里。你要让每个用户的历史行为符合逻辑喜欢风衣的用户后续加购的商品里有60%的概率也是通勤风格价格敏感型用户不该出现高价格带商品。这样生成的负样本才有意义否则协同过滤学到的全是噪声。import random import pandas as pd random.seed(42) items pd.read_csv(items.csv) # 商品表含category, style, price_band users [fU{i:03d} for i in range(1, 51)] records [] for uid in users: # 每个用户初始看3~8件商品作为“历史偏好” n_hist random.randint(3, 8) # 先随机选一个“主风格” main_style random.choice(items[style].unique()) history [] # 保证历史中至少一半商品匹配主风格 for _ in range(n_hist): if random.random() 0.6: candidate items[items[style] main_style] else: candidate items[items[style] ! main_style] item candidate.sample(1).iloc[0] records.append({ user_id: uid, item_id: item[item_id], rating: random.choice([4, 4.5, 5]), # 隐式反馈转评分 behavior: history }) history.append(item[item_id]) # 再生成“待预测”的正样本加购或收藏 for _ in range(random.randint(2, 5)): if random.random() 0.7: candidate items[items[style] main_style] else: candidate items.sample(10) item candidate.sample(1).iloc[0] records.append({ user_id: uid, item_id: item[item_id], rating: 5.0, behavior: cart }) behavior_df pd.DataFrame(records) behavior_df.to_csv(user_behavior.csv, indexFalse) print(behavior_df.groupby(user_id)[item_id].count().describe())这段脚本的关键参数是0.6和0.7它们控制偏好与随机噪声的比例。如果设为1.0数据太干净协同过滤不必要设为0.5则太乱推荐效果看不出来。我把random.seed(42)写死保证你每次跑结果一致答辩时不会因为数据变化导致演示效果不一样。注意这里把点击、收藏都映射成了高评分实际上隐式反馈转评分需要做时间衰减课程设计用统一5分就能work但论文里要说明“这是简化处理”。3.3 相似度计算与TopN推荐Python实现与参数调节现在把两种算法组合起来。基于内容的推荐函数负责召回协同过滤负责重排。我直接给一个小而完整的实现def recommend(user_id, top_n10): # 1. 找出用户历史商品 user_history behavior_df[behavior_df[user_id] user_id][item_id].tolist() if not user_history: # 冷启动返回全局热榜 return items.sort_values(hot_score, ascendingFalse)[item_id].head(top_n).tolist() # 2. 用内容相似度召回候选商品 cand_scores {} for his_id in user_history: # 用2.3的sim_matrix找到与历史商品相似的每件商品 his_idx item_list.index(his_id) for j, sim in enumerate(sim_matrix[his_idx]): if sim 0.2: continue # 相似度低于阈值的直接砍掉 cand_scores[item_list[j]] cand_scores.get(item_list[j], 0) sim # 去掉用户已买过的商品 for his_id in user_history: cand_scores.pop(his_id, None) # 3. 协同过滤重排 user_sims get_user_sims(user_id) # 复用2.2的余弦逻辑 for cand_id in cand_scores.keys(): # 对每个候选商品找相似用户对它的评分做加权 score 0 for sim_user, sim_val in user_sims.items(): r rating_matrix.loc[sim_user, cand_id] if cand_id in rating_matrix.columns else 0 if r 0: score sim_val * r cand_scores[cand_id] 0.3 * score / max(len(user_sims), 1) ranked sorted(cand_scores.items(), keylambda x: x[1], reverseTrue) return [x[0] for x in ranked[:top_n]]这里有两个重要的参数内容相似度阈值0.2和协同过滤影响系数0.3。阈值设太低候选集又杂又多设太高可能一件候选都出不来。0.3表示协同过滤在最终分数里占约三成主基调还是内容可解释。你可以调这两个数观察推荐结果差异——这是论文里“参数分析”一节的数据来源。4. 搭一层能现场演示的Web界面Flask项目结构与推荐接口4.1 Flask最小工程目录、数据流、两个核心路由后端跑通了还不够毕设要演示页面。我用Flask做因为它轻、样例多、答辩时能现场跑。典型的项目结构是这样app.py # 主程序 items.csv # 商品表 user_behavior.csv # 行为表 recsys/ __init__.py recommend.py # 推荐算法模块 templates/ index.html # 首页输入用户ID recommend.html # 推荐结果展示页 static/ style.cssapp.py只做两件事接收参数、调用推荐函数、渲染模板。不要把所有算法塞在路由里。from flask import Flask, request, render_template from recsys.recommend import recommend, load_data app Flask(__name__) # 启动时一次性加载数据避免每次请求读CSV items_df, behavior_df, sim_matrix load_data() app.route(/) def index(): return render_template(index.html) app.route(/recommend, methods[POST]) def get_recommend(): user_id request.form.get(user_id, ) if not user_id: return render_template(index.html, error请输入用户ID) top_items recommend(user_id, top_n10) # 把推荐结果关联商品详情 results items_df[items_df[item_id].isin(top_items)].to_dict(records) return render_template(recommend.html, user_iduser_id, itemsresults) if __name__ __main__: app.run(debugTrue, port8000)注意load_data()里要缓存好商品表和相似度矩阵不然每次请求重新计算页面会卡好几秒。debugTrue只在开发用答辩演示时可以开着现场报错能直接看到栈。路由提交用POST而不是GET避免URL太长也显得更正规。4.2 用模板把推荐结果渲染成“买得起”的卡片推荐页面不要在HTML里写一堆循环而是用Jinja2模板。每个推荐项做成一张卡片显示商品属性并附上一句可解释的推荐理由。!-- templates/recommend.html -- !doctype html html langzh head meta charsetutf-8 link relstylesheet href{{ url_for(static, filenamestyle.css) }} title为你推荐/title /head body h1用户 {{ user_id }} 的服饰推荐/h1 div classcard-grid {% for item in items %} div classcard h3{{ item[item_id] }} - {{ item[category] }}/h3 p颜色{{ item[color] }} 风格{{ item[style] }}/p p版型{{ item[fit] }} 季节{{ item[season] }}/p p价格带{{ item[price_band] }}/p p classreason推荐理由与历史偏好风格相似/p /div {% endfor %} /div a href/换个用户看看/a /body /html这里的“推荐理由”在真实工程里应该在recommend()里返回每个item的内容相似度来源而不是写死在页面上。你可以把recommend()的输出改成[(item_id, reason), ...]然后在模板中显示“因为你常看通勤风格所以推荐这款”。这样答辩时演示给评委看系统不再是黑匣子。4.3 项目文档怎么写从需求文档模板到答辩PPT的一句话总结源码和项目文档是交付物。很多同学重代码轻文档结果文档里只有“环境安装步骤”和“界面截图”被导师批深度不够。我习惯用这样一份自检清单来写需求分析部分要写清楚“为什么做服饰推荐而不是通用推荐”从服饰属性对决策影响大入手。概要设计画三层结构数据层CSV或SQLite、算法层召回排序、展示层Flask模板。详细设计重点写两个类ContentRecommender和CollaborativeRecommender给出类图或伪代码。测试部分写行为日志生成、推荐准确率人工评估10个用户前10个推荐里有几个让人想买。最后留一节局限与展望没有真实用户数据、未做A/B测试、可加入图片特征——这些都是老师爱问的天然问题。如果你需要项目需求说明文档模板网上能找到很多开源模板但别直接下载改个标题就交。把上面这些模块用自己的代码细节填满文档和源码对得上才是“能过”的关键。5. 服饰推荐系统的避坑清单冷启动、矩阵稀疏、数据造假和性能5.1 新用户、新商品没有评分推荐直接返回空列表现象输入一个刚注册的用户ID页面显示“暂无推荐”或者算法报KeyError。原因协同过滤依赖评分矩阵新用户在矩阵里全是0找不到相似用户新商品没有用户打过行为相似度索引也找不到它。基于内容的模块按理能解决但若你没做冷启动分支就还是一样空。解决在推荐函数开头加一个冷启动判断。新用户返回全局热榜即hot_score最高的前10件商品新商品则在内容召回阶段采用“同品类随机替补”策略把候选集里同类目但销量最高的商品顶上去。我一般在recommend()里先检查用户历史记录长度小于1就直接走热榜函数。5.2 用one-hot向量算余弦相似度结果全是0现象基于内容的推荐代码跑通了但打印相似度时大部分都是0偶尔出个1推荐结果乱七八糟。原因服饰标签经过CountVectorizer后是高维稀疏向量如果两件商品没有共同词余弦就是0。比如A是“黑色风衣”B是“白色T恤”它俩确实没有共同标签余弦为0是数学上对的但对用户来说“它们都是春季可穿”应该有一点相似。这暴露的是特征设计问题而不是算法问题。解决在标签里加入人工抽象的粗粒度特征比如“春季通勤”“夏季休闲”这种场景词而不是只有商品客观属性。还可以把价格带转化为序数特征加权参与相似度。我建议你构造标签时至少包含风格品类场景这三个维度别只堆颜色。5.3 答辩老师追问“评分数据哪来的”你说“模拟的”然后被连环炮现象演示很顺利老师突然问你这个评分矩阵是真实数据吗你答模拟的。他接下来就问那你的推荐结果为什么可信现场卡壳。原因这里的坑不是不可以用模拟数据而是在项目文档和演示中没有把“数据生成规则”本身作为一项工作展示出来。老师要听的是你理解这些数据在现实世界中代表什么以及你怎么把无行为日志的问题控制在课题范围内。解决准备一张“数据生成合理性”的PPT展示页放上5.2节的生成脚本关键逻辑用户主风格概率、价格带与人群的关联、隐式行为到评分的映射规则。同时提前准备好一句话回法“本课题聚焦于推荐算法与系统实现因此用规则化数据模拟了用户行为真实场景下可将这份接口替换为埋点日志这也是后续工作之一。”5.4 商品数量到5000后相似度矩阵变得又大又慢现象数据从100件加到几千件cosine_similarity计算完矩阵内存占用好几个G页面响应时间几十秒。原因全量两两计算相似度复杂度是O(n^2)存储也相应为n^2。课程设计可能只有几百件但文档里写着“可扩展到电商数据”就需要考虑效率问题。解决推荐用的相似度矩阵只保留每件商品最相似的TopK件比如K50用nearest_neighbors近似或直接在余弦矩阵上切片。另一个常用做法是用TfidfVectorizer先做降权和过滤减少稀疏度。我给毕设项目的建议是如果商品在5000以内按天预计算相似度并保存为sim_matrix.npy运行时加载别每次启动重新算。6. 进阶把推荐从“能跑”调到“像样”并做离线验证6.1 给服饰标签加显式权重把用户历史行为的品类偏好带进去默认的基于内容推荐对用户历史中每件商品的相似度打分是等权相加。这不符合实际用户可能只是上周偶然看了件风衣但连衣裙加购过三次。改进方式是在召回阶段给历史商品分配权重权重来自行为类型加购记1.0收藏记0.7点击记0.3。6.2 离线验证按用户留出数据计算Hit Rate算法改完总得自测。我习惯把每个用户的行为按时间排序最后1次加购作为测试项前面的作为历史然后跑推荐看测试商品是否出现在Top10里统计命中率。命中率高于20%就算这个方案在模拟数据上明显有效。你在论文里放这个指标比“平均准确率98%”这种没来由的数字可信。6.3 我习惯留着的三层日志以及一条快速调试命令我在项目里放三层日志算法层记录每一次召回的候选集大小路由层记录用户ID、推荐商品个数和耗时数据层记录CSV文件加载的行数和缺失值。这样现场出问题口头汇报能张口就来。调试时最常用的一句命令是python -m pytest tests/ -k recommend跑通最小用例再开页面。把这个项目调到这个程度我自己的习惯是把“参数实验”和“人工抽检”结果单独存到一个Excel里留档。这个习惯帮我避免过很多次答辩前推翻重做的局面。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →