十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

农产品智能推荐:协同过滤、特征工程与评价指标实战

农产品智能推荐:协同过滤、特征工程与评价指标实战 简介这是一篇西南财经大学学士学位毕业论文聚焦协同过滤算法在农产品智能推荐系统中的落地应用适合计算机、数据科学与人工智能专业的本科生、研究生及推荐算法初学者作为选题参考与写作范例。全文从绪论、协同过滤算法基础、农产品智能推荐系统设计到算法应用、实验与结果分析层层展开系统讲解了基于用户与基于物品两类协同过滤的实现思路并讨论了冷启动、数据稀疏、计算复杂度等典型问题及其改进方向同时结合农产品的季节性、地域性与新鲜度等特征给出推荐模型设计与准确率、覆盖率、多样性等评价指标的使用方法。压缩包仅含1个docx文件约32KB篇幅完整、结构规范可直接用于毕业论文撰写、算法复现与学术研究参考。目前已有302人学习便于读者快速搭建研究框架并对照实验设计开展实践。1. 农产品推荐场景下的协同过滤这篇毕业论文的立足点推荐系统在工业品上早就跑通了搬到农产品上却经常翻车。原因不难理解农产品的候选集合带极强的时令性和地域性苹果的评分随季节波动同一颗脐橙在不同产地用户眼里完全不是一回事。这份来自西南财经大学的学士学位论文《协同过滤算法在农产品智能推荐系统中的应用研究》正是围绕这些真实约束展开的。它没有停留在概念复述而是完整走了一遍「算法原理梳理 → 评分矩阵建模 → 农产品特征提取 → 实验设计与指标评估」的链条。协同过滤算法、农产品特征提取方法、评价指标这三块是骨架。对于正在做毕业设计、需要一份可直接复现研究框架的计算机与数据科学方向学生它的价值不在结论而在于把每一步的输入、输出和踩坑点都留了下来。2. 用户-农产品评分矩阵与相似度计算的地基协同过滤的第一件事不是写算法而是把用户对农产品的隐含偏好变成一张结构化矩阵。矩阵建不好后面再花哨的相似度都是空中楼阁。2.1 评分矩阵构建与农产品数据稀疏性用户-物品评分矩阵的行是用户列是农产品单元格是显式评分或隐式行为加权值。农产品场景的麻烦在于一个用户一年可能只买三五次生鲜矩阵稀疏度动辄超过 99%。论文里提到把浏览、收藏、复购折算成隐式评分这是常见做法。import numpy as np import pandas as pd # 用户-农产品评分矩阵行是用户列是农产品 # 0 表示未交互不是评分为0 ratings pd.DataFrame( [[5, 4, 0, 0, 3], [4, 0, 5, 3, 0], [0, 3, 4, 5, 4], [0, 0, 3, 4, 5]], index[u1, u2, u3, u4], columns[苹果, 大米, 脐橙, 春茶, 小龙虾] ) # 稀疏度 未交互单元格 / 总单元格 sparsity (ratings.values 0).sum() / ratings.size print(f稀疏度: {sparsity:.2%})参数说明0在这里被约定为「无交互」而非「差评」这是协同过滤的通用约定一旦把 0 当成真实评分参与均值计算结果会严重偏移。稀疏度公式用于判断是否需要引入矩阵分解或混合策略。2.2 余弦、皮尔逊与杰卡德相似度的选型三种相似度各有适用边界论文第二章做了对比但落代码时容易混用。余弦相似度对评分绝对值不敏感适合只看方向一致性的场景皮尔逊做中心化处理能抵消不同用户打分尺度差异杰卡德只关心有没有共同交互适合隐式反馈。相似度方法计算依据适用场景注意点余弦相似度向量夹角显式评分、稠密矩阵未中心化受打分尺度影响皮尔逊相关系数中心化后夹角用户评分尺度差异大共同评分项少于 2 时无意义杰卡德相似度交集/并集隐式反馈浏览、购买忽略评分强度只看有无def cosine_sim(mat): # 仅在共同评分维度上计算避免 0 填充带来偏差 sim np.zeros((mat.shape[0], mat.shape[0])) for i in range(mat.shape[0]): for j in range(mat.shape[0]): a, b mat[i], mat[j] mask (a 0) (b 0) # 只取共同评分项 if mask.sum() 0: continue va, vb a[mask], b[mask] sim[i, j] np.dot(va, vb) / (np.linalg.norm(va) * np.linalg.norm(vb)) return sim def pearson_sim(mat): sim np.zeros((mat.shape[0], mat.shape[0])) for i in range(mat.shape[0]): for j in range(mat.shape[0]): a, b mat[i], mat[j] mask (a 0) (b 0) if mask.sum() 2: # 皮尔逊至少需要 2 个共同评分点 continue va, vb a[mask], b[mask] va_c, vb_c va - va.mean(), vb - vb.mean() # 中心化 denom np.linalg.norm(va_c) * np.linalg.norm(vb_c) sim[i, j] np.dot(va_c, vb_c) / denom if denom else 0 return sim sim_cos cosine_sim(ratings.values) sim_pea pearson_sim(ratings.values) print(pd.DataFrame(sim_cos, indexratings.index, columnsratings.index).round(3))逻辑说明mask是稀疏场景下的关键只在共同评分项上算距离避免用 0 填充拉低相似度。皮尔逊的mask.sum() 2判断不能省否则方差为 0 会直接除零。np.linalg.norm求 L2 范数是余弦与皮尔逊分母的公共部分。2.3 UserCF 与 ItemCF 两条路线的取舍UserCF 找相似用户用邻居买过的农产品推荐给目标用户适合用户兴趣稳定、社交传播强的场景ItemCF 找相似农产品用目标用户历史偏好物品的相似物做推荐物品数量远小于用户数量时计算更省也更适合农产品这种「物品更新慢、用户流动快」的结构。论文第四章分别给出了两者在用户推荐与物品推荐中的落点实践里更常见的做法是 ItemCF 打底UserCF 做冷启动兜底。3. 农产品特征工程与推荐模型设计落地评分矩阵只描述了「谁喜欢什么」但农产品推荐必须解释「为什么推荐这个」。第三章的价值就在于把产地、品种、季节、新鲜度这些农产品专有特征接进推荐模型。3.1 农产品特征提取产地、品种、季节性与新鲜度农产品的特征分两类静态属性产地、品种、品类和动态属性季节、新鲜度衰减。静态属性适合独热编码后计算物品相似度动态属性则要做归一化并参与打分修正。常见做法是给新鲜度加一个时间衰减因子让邻近采摘期的农产品权重更高。import numpy as np import pandas as pd from sklearn.preprocessing import OneHotEncoder, MinMaxScaler # 农产品基础属性表 goods pd.DataFrame({ item: [苹果, 大米, 脐橙, 春茶, 小龙虾], origin: [山东, 黑龙江, 江西, 浙江, 湖北], category: [水果, 粮油, 水果, 饮品, 水产], season: [秋, 全年, 冬, 春, 夏], fresh_days: [7, 180, 10, 365, 3], # 保鲜期反映新鲜度衰减速度 }) # 类别型特征独热编码 enc OneHotEncoder(sparse_outputFalse) cat_feat enc.fit_transform(goods[[origin, category, season]]) # 数值特征归一化后反转保鲜期越短新鲜度权重越高 scaler MinMaxScaler() num_feat 1 - scaler.fit_transform(goods[[fresh_days]]) item_feature np.hstack([cat_feat, num_feat]) print(item_feature.shape) # (5, 10)参数说明fresh_days表示从采摘到品质明显下降的天数1 - MinMaxScaler的用途是把「保鲜期长」转成「新鲜度权重低」让小龙虾这类易腐品在推荐中权重更突出。OneHotEncoder输出维度 各原始列取值数之和。3.2 用户画像与评分模型设计用户画像由三部分组成人口属性地域、消费能力、行为属性复购率、浏览品类分布、偏好属性口味、价格敏感度。论文把这三条拼成用户向量后与评分矩阵做加权融合形成最终的用户-物品关联矩阵。实践里我一般会留一个权重系数alpha控制行为数据与画像数据的占比冷启动用户调高画像权重老用户调高行为权重。3.3 推荐流程与邻域选取推荐生成三步算相似度矩阵 → 选取 Top-N 邻居 → 加权预测评分并排序。邻居数量 N 直接影响推荐质量N 太小容易过拟合少数邻居N 太大引入噪声。def predict_score(user_idx, item_idx, sim, mat, k2): # 取与目标用户相似度最高的 k 个邻居 sims sim[user_idx].copy() sims[user_idx] 0 # 排除自己 neighbors np.argsort(sims)[::-1][:k] num, den 0.0, 0.0 for n in neighbors: r mat[n, item_idx] if r 0: # 邻居也没交互过跳过 continue num sims[n] * r den abs(sims[n]) return num / den if den else 0逻辑说明sims[user_idx] 0是必须的一步否则自己与自己的相似度会污染邻居排序。r 0跳过无交互邻居避免把「没买过」误算成「评分 0」。最终评分是相似度加权平均den用绝对值是为了处理负相似度的情况。4. 离线实验与评价指标准确率、召回率、覆盖率怎么算第五章的实验设计是整篇论文最能体现工程能力的地方。推荐系统的实验不能只看准确率论文引入了准确率、召回率、覆盖率、多样性四类指标这里把计算方式拆开。4.1 数据集划分与离线实验设计推荐系统的数据划分不能用随机切分否则会用「未来行为」预测「过去行为」。正确做法是按时间切分前 80% 时间窗作为训练集后 20% 作为测试集同时保证每个用户在测试集中至少有一条交互记录。指标含义计算口径目标方向准确率 PrecisionK推荐列表中用户真实交互的占比命中数 / (用户数 × K)越高越好召回率 RecallK真实交互被推荐覆盖的比例命中数 / 测试集交互总数越高越好覆盖率 Coverage被推荐过的物品占全部物品的比例推荐物品去重数 / 物品总数越高越好多样性 Diversity推荐列表中物品类别的分散程度类别分布熵视场景而定4.2 评价指标的代码实现def precision_recall_at_k(recommend, ground_truth, k10): # recommend: {user: [item, ...]} 按分数降序 # ground_truth: {user: set(items)} 测试集中的真实交互 hit 0 for u, items in recommend.items(): topk items[:k] hit len(set(topk) set(ground_truth.get(u, []))) precision hit / (len(recommend) * k) recall hit / sum(len(v) for v in ground_truth.values()) return precision, recall def coverage(recommend, all_items): rec_items set() for items in recommend.values(): rec_items.update(items) return len(rec_items) / len(all_items)逻辑说明hit统计所有用户 Top-K 推荐列表与真实交互的交集总数。准确率的分母是用户数乘 K召回率的分母是测试集交互总量两者对同一份推荐结果的方向往往相反需要一起看。coverage的计算更直接统计推荐系统实际吐出的物品去重数占全部物品的比例能暴露推荐结果是否过度集中在少数热门农产品上。4.3 冷启动与数据稀疏的排错冷启动分用户冷启动和物品冷启动。用户冷启动在农产品系统里尤其常见解决方法通常是引入注册地域和季节作为先验用基于内容的方式先推出几条候选等积累足够行为再切回协同过滤。数据稀疏问题除了矩阵分解另一个立竿见影的手段是降低相似度计算的共同评分阈值但阈值不能无限降降到 0 就退化成噪声匹配。实践里我一般会把最小共同评分项数设为 2再配合 ItemCF 弥补用户侧数据不足。5. 混合推荐与论文复现的实操技巧协同过滤单独跑在农产品数据上指标往往上不去混合是绕不开的一步。加权混合最省事把协同过滤和基于内容的推荐分数按系数相加def hybrid_score(cf_score, cb_score, alpha0.7): # alpha 越大协同过滤占比越高 return alpha * cf_score (1 - alpha) * cb_scorealpha要靠离线实验调常见范围在 0.5 到 0.8 之间。农产品场景里新用户和历史行为少的物品调到 0.5 以下更稳老用户和长销品可以拉到 0.8。切换混合则更适合有明显场景边界的系统比如节日促销期用基于内容的规则兜底日常用协同过滤主推。复现论文实验时最容易翻车的两点一是随机种子不固定Word2Vec 或矩阵分解的初始化会让每次结果不一样务必在代码顶部设np.random.seed(42)二是评价指标的 K 值不统一论文写 Recall10自己跑 Recall20数据根本不可比。固定 K 值、固定切分脚本、固定种子这三个条件满足后同一套代码在本地复现的波动可以压到 1% 以内。另外一个细节是稀疏度统计要在构建矩阵之后立刻打印一旦发现稀疏度低于 90%多半是评分数据里混进了 0 值填充得回头查数据预处理那一步。本文还有配套的精品资源点击获取
返回列表