ARTICLE DETAIL

资讯详情

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

改进型SVD协同过滤:新闻推荐中的时间衰减与矩阵分解实践

改进型SVD协同过滤:新闻推荐中的时间衰减与矩阵分解实践 简介面向计算机科学、数据科学、人工智能等专业学生及推荐算法研究者这是一份可直接参考的学士学位毕业论文围绕新闻推荐场景深入探讨改进型SVD协同过滤算法的设计与实现。论文从协同过滤原理出发针对传统SVD在稀疏性、冷启动、过拟合与动态更新方面的不足给出了矩阵分解改进思路、详细算法流程、数据预处理及实验评估过程并完整设计了新闻推荐系统需求分析与实现方案。适用于学术研究、毕业论文撰写及算法实现等场景。资源为单个docx文档压缩包约35KB内容包含摘要、绪论、相关技术综述、改进算法设计实现、系统设计等章节结构清晰便于快速定位阅读。目前已有257人学习下载读者可从中获取充分的算法描述、实验设计和结果分析并以此为基础开展进一步研究与改进。1. 新闻推荐场景下改进型SVD协同过滤到底改在哪新闻推荐系统里用得最多的算法链路是行为召回加排序但基于用户和物品交互矩阵的协同过滤一直没有退场尤其是在信息流和快讯这类物品更新很快的场景。标准SVD在新闻场景里成功率偏低核心在于新闻生命周期以小时计、用户兴趣随时间漂移而SVD默认把用户-新闻矩阵当成静态快照来分解天然跟新闻的节奏冲突。改进型SVD的改动并不花哨在矩阵分解中显式加入时间衰减、偏差项和正则约束让隐因子更多表征近期兴趣结构同时缓解新用户和长尾新闻带来的稀疏问题。实际落地时很多人一上来就把衰减系数和隐因子维度随意设置训练和评测完全脱节效果还不如直接推热门。做推荐算法或后端数据开发的工程师读完这篇能快速理解改进型SVD在新闻推荐里为什么成立、怎样训练、上线时又该盯哪些指标。下面按“问题拆解、建模实现、评测与召回、上线调参”这条主线展开每一章都能直接对应到工程代码。2. 从SVD到改进型SVD把新闻矩阵的稀疏与时序问题翻译成建模语言2.1 标准SVD做的事情是把高维稀疏矩阵压成低维隐因子标准SVD的工业落地版本很多最常用的是Funk-SVD及其变体。核心思路是把用户u对新闻i的评分r_ui预测成用户向量p_u与物品向量q_i的点积训练时让已有交互位置的预测误差尽量小。完整一点的表达式是rhat_ui μ b_u b_i p_u · q_i这里μ是全局均值b_u是用户偏差b_i是物品偏差。如果只保留点积项那是朴素的“纯SVD”加上这三项才是工业里最常见的带偏置矩阵分解。放在新闻推荐这个场景里三种偏差不是装饰不同用户的点击频次差异极大同一条新闻放在头条还是末条产生的点击率也完全不同。用户偏差吸收个人活跃度差异物品偏差吸收新闻的自然热度剩下的隐因子才真正刻画“谁对哪类内容有偏好”。新闻推荐里通常没有真正的评分。用户行为只有曝光、点击、停留时长、分享等隐式反馈常见做法是把正向行为映射成置信度权重点击计0.6、完读计0.8、收藏计1.0再配合负样本计0。这个映射关系直接决定了矩阵里每个值的物理含义比后面任何优化器超参都更影响结果。把点击和收藏都写成1分等于告诉模型这两种行为价值相同推荐排序会被低质点击带偏。2.2 新闻矩阵的三条时间特性静态SVD一条都扛不住第一个是时效性。一条新闻的有效期往往只有几小时到几十小时而电影能在评分网站上活跃半年以上。矩阵把昨天的大热点和三个月前的旧闻同等对待SVD训练出的隐因子会朝“历史平均兴趣”收敛。第二个是兴趣漂移。用户不是匀速地保持对某个主题的热度。赛事、突发、假期等因素都会让兴趣短期剧烈跳动。静态矩阵把这种短时波峰当作长期兴趣记录下来典型后果是给用户推一堆已经过气但分数很高的旧闻。第三个是行为稀疏。新闻产品不像电商有购物车和收藏夹多数用户一天只产生几次到十几次点击。相对几十万甚至上百万的活跃新闻池这是一个密度极低的矩阵。常规SVD在两个稀疏用户共同点击很少时相似度估计的方差会非常大推荐结果看起来就跟随机差不多。把这三条翻译成建模语言结论非常直接样本不能平等参与训练不同时间点发生的交互必须以不同权重进入目标函数。滑动窗口的长度T通常取7到14天比7天短模型学不到跨周的兴趣规律比14天长训练集又被大量过时交互稀释。T的取值尽量与业务里新闻的平均生命周期对齐这是后面所有改进的前提。2.3 改进型SVD的三个骨架偏差分解、时间衰减、局部协同改进型SVD并没有颠覆矩阵分解的基本形式而是在损失函数上做三个关键改动改进模块解决问题实现形态偏差分解用户习惯差异与新闻本身热度μ b_u b_i时间衰减新闻时效性与兴趣漂移样本权重 w(t) e^{-α·Δt}局部化训练稀疏矩阵下的实时性最近T天窗口训练 全局向量兜底偏差分解解决基准线的准确度时间衰减决定训练时每条样本的信赖程度局部化训练保证模型不会被几十天前的旧交互拖住。Δt是交互时间与当前训练时间的差值α是衰减系数典型取值范围在0.005到0.05之间。α太小时间衰减约等于没加α太大模型对近一两个小时的点击敏感度太高容易产生抖动。这里还有一个选型问题用交替最小二乘法还是随机梯度下降新闻场景的交互量通常在千万到亿级交替最小二乘做全局更新方便但内存压力大而且不好支持增量。随机梯度下降配合Mini-batch更容易实现小时级增量更新也更适合新闻这种需要高频重训的业务形态。3. 改进型SVD协同过滤的建模与最小可复现实现3.1 损失函数只改一处稀疏加权就成了时间衰减把时间衰减纳入SVD最干净的做法是给每个交互样本乘一个权重。带偏置和时间衰减的改进型SVD损失函数写成L Σ w(t_ui)·( r_ui - μ - b_u - b_i - p_u·q_i )² λ(‖p_u‖² ‖q_i‖² b_u² b_i²)和普通矩阵分解的目标式子相比区别只在两点第一r_ui不是原始打分而是行为权重映射后的值第二每个样本根据时间戳单独计算w(t_ui)而不是按天做样本重采样。这样训练时自然会把昨天的点击排在三周前的点击前面。λ正则系数也不建议所有参数共用一个值。有人把b_u、b_i、p_u、q_i的λ合并成一个常数工程上会限制调参空间。用户偏差的幅度天然比物品偏差大分开设λ_bu、λ_bi、λ_factor三个值调起来更灵活通常λ_bu取0.05、λ_bi取0.02、λ_factor取0.02作为起点。3.2 一个能本地跑通的改进型SVD训练器Python下面是一个最小实现输入是含uid、iid、timestamp、rating字段的DataFrame其中rating已经是行为加权后的置信度。它把时间衰减、偏差、正则全部放进去几万条数据可以直接在笔记本上跑。import numpy as np import pandas as pd class TimeDecaySVD: def __init__(self, n_factors20, alpha0.01, lr0.02, reg0.02, n_epochs10): self.n_factors n_factors # 隐因子维度 self.alpha alpha # 小时级时间衰减系数 self.lr lr # 学习率 self.reg reg # L2正则系数 self.n_epochs n_epochs def fit(self, df, t_now): self.user_ids df[uid].unique() self.item_ids df[iid].unique() self.user_map {u: i for i, u in enumerate(self.user_ids)} self.item_map {i: j for j, i in enumerate(self.item_ids)} rng np.random.default_rng(42) self.p rng.normal(0, 0.1, (len(self.user_ids), self.n_factors)) self.q rng.normal(0, 0.1, (len(self.item_ids), self.n_factors)) self.bu np.zeros(len(self.user_ids)) self.bi np.zeros(len(self.item_ids)) self.mu df[rating].mean() for epoch in range(self.n_epochs): # 逐行更新按样本时间戳计算衰减权重 for row in df.itertuples(): u self.user_map[getattr(row, uid)] i self.item_map[getattr(row, iid)] delta_t t_now - getattr(row, timestamp) w np.exp(-self.alpha * max(delta_t, 0)) r getattr(row, rating) pred self.mu self.bu[u] self.bi[i] self.p[u].dot(self.q[i]) e (r - pred) * w self.bu[u] self.lr * (e - self.reg * self.bu[u]) self.bi[i] self.lr * (e - self.reg * self.bi[i]) self.p[u] self.lr * (e * self.q[i] - self.reg * self.p[u]) self.q[i] self.lr * (e * self.p[u] - self.reg * self.q[i]) def predict(self, uid, iid): u self.user_map.get(uid) i self.item_map.get(iid) if u is None or i is None: return self.mu return self.mu self.bu[u] self.bi[i] self.p[u].dot(self.q[i])这个实现的核心在e (r - pred) * w这一行。梯度里乘上w之后交互发生时间离当前越久这一条样本对向量更新的贡献就越小等价于在损失函数每一项前乘了衰减权重。参数怎么给n_factors取20是适合中等稀疏度的稳妥起点alpha0.01意味着30小时前的样本权重约0.74100小时前约0.37符合新闻以天为周期的业务直觉lr取0.02是避免在稀疏数据上大幅振荡的经验值reg0.02用来约束隐因子范数样本量增大后可以适当提高到0.05。注意timestamp和t_now必须使用同一个时间单位。上面的实现按小时算如果拿到的是秒级时间戳要先把差值除以3600再传给max(delta_t, 0)否则衰减会瞬间归零。3.3 为什么线上版本不用逐行更新上面的循环写法拿来做效果验证很方便但速度过慢。线上版本一般有两个改造方向一是把数据按小时分桶桶内样本共用同一个衰减权重这样可以用稀疏矩阵乘法批量更新二是直接落到PyTorch的Embedding层上把b_u、b_i当作一维向量参数用优化器自动求导。两种方式都能完成梯度更新选择依据是团队对运维复杂度的容忍度。推荐先用分桶方案因为它只改数据层不需要引入深度学习框架。4. 新闻推荐系统的搭建、评测与混合召回策略4.1 从点击日志到训练矩阵行为加权和负样本处理新闻推荐没有显式评分构造训练矩阵这一步决定了整个模型的上限。常见做法是把曝光未点击记为0点击记0.6点击并停留超过30秒记0.8完整阅读或收藏记1.0。这样做相当于把置信度差异写到训练样本的值里模型会优先拟合那些带强烈正向信号的交互。负样本不能省。如果训练集里只有正样本SVD会倾向于把所有预测值抬高排序失去区分度。一般做法是按曝光未点击行为做随机负采样与正样本按1:2或1:3比例混合负样本的rating填0timestamp取曝光时刻而不是当前时刻。这个细节很多人会漏掉负样本的时间戳如果写错时间衰减权重就失去意义新老样本的对比会失真。4.2 离线评测指标怎么选才不会自欺欺人新闻推荐的离线评测一般不把RMSE当唯一标准因为RMSE对排序的指示作用很弱。实用上更关注下面这组组合指标计算方式在新闻推荐里的含义HitRateK用户实际点击的新闻是否出现在Top-K判断推荐列表能否命中兴趣长尾覆盖率推荐出新闻数 / 当日全量新闻数检验改进型SVD是否只堆头部热门时效性命中率列表中24小时内发布的新闻占比验证时间衰减是否生效RMSE预测值的均方根误差保留但不作为主要排序依据几个经验值可以参考HitRate10做到0.25以上说明模型基本学到了用户结构长尾覆盖率低于0.3优先怀疑alpha设置过小模型又把历史长尾拉了出来时效性命中率偏低去看训练数据的timestamp是否对齐是否存在批量导入导致时间戳全部相同的脏数据。另外离线评测的数据划分必须严格按时间切不能随机切分。随机切分会让训练集里出现与验证集同族的新闻时间衰减这个改进点的收益会被完全掩盖。用“前6天训练、第7天验证”的切法衰减项的增益才能显性化。4.3 混合召回改进型SVD之外还要并行几条通道实际新闻推荐系统里改进型SVD只负责兴趣主通道。还需要内容召回匹配用户最近的阅读主题、热点召回突发新闻、近邻协同召回。多路召回的结果要融合常见做法是线性加权。先对每路分数做z-score归一化再按权重融合def merge_recalls(user_id, k10): svd_items svd_recommend(user_id, topk10) # 改进型SVD主通道 content_items content_recommend(user_id, topk10) # 内容相似召回 hot_items hot_news_recommend(topk5) # 热门兜底 merged {} for item, score in svd_items: merged[item] merged.get(item, 0) 0.6 * score for item, score in content_items: merged[item] merged.get(item, 0) 0.3 * score for item, score in hot_items: merged[item] merged.get(item, 0) 0.1 * score return sorted(merged.items(), keylambda x: x[1], reverseTrue)[:k]权重0.6/0.3/0.1是常见起点不建议一上来就固定。资讯突发型产品可以把热门权重提到0.3垂直阅读型产品可以加大内容相似度权重到0.4每次调整后都要重看一遍4.2节的三个指标而不是只看单次点击率。三路分数的量纲不一致直接相加会让数值大的那一路占据绝对优势归一化这步不能省。5. 上线前的验证与三个值得收藏的调参细节5.1 用最近一周的验证集挑alpha和隐因子维度alpha不是拍脑袋定的。常见做法是固定最近7天数据前6天训练、第7天做验证画出alpha从0.002到0.1的HitRate10变化曲线取曲线平稳段靠左的值作为线上配置。小时粒度数据下alpha通常在0.01到0.03之间日粒度数据则要缩小约10倍。隐因子维度不要盲目堆高新闻推荐场景里k取10到30就够用户平均交互次数低于10时取10更稳妥。5.2 冷启动兜底向量池和组均值替代新用户进入系统时没有对应的p_u。常见做法是按年龄段、地域等粗粒度属性对用户分组用组内老用户的平均向量作为新用户初始向量再随着点击行为做增量更新。新上线的新闻没有q_i则用同类目新闻向量的均值初始化。这个方法成本低、可解释性强比单独训练一套冷启动模型更可控。5.3 线上指标跟踪和对照组设置上线后重点看小时级指标点击率、次点击率、单用户阅读时长、人均阅读条数。时间衰减对点击率的提升通常不是当晚就能看出来的需要至少跑三天。对照组建议直接在现有线上版本上叠加相同的时间衰减权重而不动整个SVD结构单独验证衰减项的收益。这样得到的增量更干净排错时只需要追一条链路的数据口径。本文还有配套的精品资源点击获取
返回列表