尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Memory-Based协同过滤全解析:从评分矩阵到相似度计算与工程落地

发布时间:2026/9/9 4:30:45

资讯中心
01
ARTICLE

Memory-Based协同过滤全解析:从评分矩阵到相似度计算与工程落地

Memory-Based协同过滤全解析:从评分矩阵到相似度计算与工程落地
1. 为什么在深度学习时代还要啃内存式协同过滤先说个身边场景你在旅游App刷完杭州西湖的攻略底下给你推了西溪湿地、乌镇。表面看是系统很懂你实际上它可能根本不知道西湖有多美它只是记住了——之前和你行为很相似的那批人看完西湖之后还点了什么。这个记忆并查找相似关系的过程就是基于内存的协同过滤英文叫Memory-Based Collaborative Filtering简称Memory-Based CF。这篇是这个系列笔记的第二篇我打算把Memory-Based CF的来龙去脉一次讲透。它适合什么人看正在系统学推荐系统、但被各种深度学习模型绕晕的初学者以及需要快速给业务拉一个可解释基线方案的工程同学。读完之后你能搞清楚User-Based和Item-Based两条路线的完整计算流程、相似度怎么选、预测公式为什么长那样、真实项目里会踩哪些坑。1.1 记忆就是一切Memory-Based CF 到底是什么Memory-Based CF从名字上拆开看Memory指的是算法运行时直接使用用户的历史行为数据——也就是用户和物品之间的交互记录比如评分、点击、收藏、购买。它不像矩阵分解或者深度学习那样先把数据压成一套隐向量而是把这些历史记录当成记忆直接参与计算用户来了就靠这份记忆找相似用户、找相似物品。它包含两个经典分支User-Based Collaborative Filtering基于用户的协同过滤核心是和你口味相似的人喜欢了什么就给你推荐什么Item-Based Collaborative Filtering基于物品的协同过滤核心是你喜欢的这个物品和哪个物品长得像就推荐那个。很多人第一次学到这里会有一个疑惑既然深度学习都这么强了为什么还要先啃这种土办法我的答案是协同过滤是整个推荐系统里少有的、用一句话就能解释清楚的推荐逻辑它给后面所有复杂模型提供了效果底线和可解释性参照。你把Memory-Based CF吃透再去看矩阵分解、神经协同过滤会发现它们的核心还是在做同一件事描述用户和物品之间的相似关系。1.2 现用现算和训练模型的本质差异Memory-Based这个词是相对于Model-Based基于模型的协同过滤而言的。Model-Based方法会预先训练一个模型把用户和物品映射到低维向量空间预测时靠模型参数算出一个分数而Memory-Based方法没有显式的训练过程它是在收到推荐请求后直接在当前这份历史数据上找相似关系。用生活里的类比来讲Memory-Based像一个从业十几年的老店员你进店说想看悬疑小说他凭脑子里记住的像你这样的客人最后都买了东野圭吾来给你推荐Model-Based则像一个统计学家他先收集几千个顾客的购买记录归纳出喜欢东野圭吾的人往往也喜欢紫金陈然后用这个统计规律来推荐。前者依赖的是活生生的记忆后者依赖的是归纳出来的规律。这种现用现算的特性带来两个直接结果一是解释性特别好你能明确说出因为用户A和目标用户口味相似并且A给这个物品打了高分所以推荐给你二是实现简单不需要训练超参甚至不需要GPU。代价是当数据量特别大时每一次在线计算相似度的开销都很大所以工程上通常会做一些预计算和缓存这个我放到第7章详细讲。1.3 依然值得学的三个理由第一可解释性。因为你喜欢的物品和另一个物品相似度很高所以推荐它这句话产品经理和用户都听得懂。在很多场景尤其电商、酒旅、内容社区可解释性直接和转化率挂钩用户看到一个莫名其妙的推荐是会流失的。第二它是完美的Baseline。我做推荐项目时有个习惯任何新模型上线前必须先跟一套Memory-Based CF对比。如果深度学习模型连一个相似度加权都打不过那说明要么特征没做好要么数据量根本不够支撑复杂模型。第三小数据场景下它是真正的生产力。很多垂直领域的推荐系统比如某个只有几千用户的旅游攻略站用户交互矩阵非常稀疏复杂的图神经网络根本学不出来但一个朴素的Item-Based CF反而能给出稳定且合理的结果。这也就是为什么协同过滤算法旅游推荐系统这样的需求一直没消失——它简单但它在很多真实场景里就是够用。2. 一切从评分矩阵开始读懂用户-物品交互表无论是User-Based还是Item-Based所有Memory-Based CF的起点都是同一张表用户-物品交互矩阵。搞清楚这张表长什么样后面所有计算都只是围绕它转。2.1 用一张景点评分表理解数据形态假设我们做一个旅游推荐系统数据里有5个用户A、B、C、D、E5个景点西湖、灵隐寺、乌镇、西溪湿地、千岛湖用户给景点打分分值1到50表示没去过、没评分。那么评分矩阵就是这样用户西湖灵隐寺乌镇西溪湿地千岛湖A42334B55143C5?143D24421E12512行是用户列是物品交叉点就是交互记录。我们假设用户C去过西湖、乌镇、西溪湿地、千岛湖但没去过灵隐寺现在要预测的就是C会给灵隐寺打几分。这张表就是记忆的全部载体。User-Based走路是按行看找到和C这一行最像的其他行让它们来填C的空缺Item-Based走路是按列看找到灵隐寺这一列和其他列的关系用C已经打过分的数据来推测空缺值。本质上都是矩阵操作只是看矩阵的方向不同。2.2 稀疏性Memory-Based 方法最大的隐形敌人真实场景的评分矩阵不会像我上面这张表这么清爽。一个电商平台可能有1亿用户、1000万商品但一个用户一辈子都不会和超过几百个商品发生交互矩阵里99.9%以上的位置都是空白。这就叫稀疏性它是Memory-Based CF最核心的敌人。因为相似度计算依赖两个用户共同评分过的物品如果A只看过西湖B只看过千岛湖两人没有任何交集那他们之间的相似度就只能算0没法建立联系。更麻烦的是即使有交集如果交集只有1-2个物品算出来的相似度也非常不可靠可能纯属偶然。所以我一直强调学习阶段用小矩阵理解公式没问题但脑子里要绷着一根弦这些公式在稀疏矩阵上跑出来是什么样和教科书案例完全是两码事。后面我会单独用一章讲这些坑。2.3 显式反馈与隐式反馈的不同处理方式评分矩阵里的值不一定是分数它还分显式反馈和隐式反馈。显式反馈就是用户明确表达喜好的行为典型的是1-5星评分、点赞、点踩。它的优点是信号明确5分就是喜欢1分就是不喜欢缺点是数据往往很稀疏因为用户主动评分的行为成本太高了。隐式反馈是用户无意识留下的行为痕迹比如点击了商品详情页、收藏了攻略、播放了30秒视频、在酒店详情页停留了2分钟。它的优点是数据量大几乎每个用户每天都会产生缺点是没有明确的负样本没点击不代表不喜欢可能是根本没看到。Memory-Based CF处理这两类数据的方式不太一样。显式评分直接用皮尔逊相关系数这类方法效果最好而隐式反馈通常会被转成0/1的二值化表示点击过记1没点击记0然后相似度的计算往往就会换成接下来会讲到的Jaccard相似度。这在我实践里是个非常重要的区分点拿二值化的点击数据去算皮尔逊相似度虽然也能出结果但对评分尺度的理解会变形效果通常不如直接算Jaccard或余弦。3. User-Based CF找到品味相近的人再让他们帮忙打分User-Based CF是最早被提出、也最符合直觉的协同过滤思路。它做的事情可以总结成一句话如果你和一群用户在历史行为上很像那这群用户喜欢但你还没看过的东西大概率你也会喜欢。3.1 完整工作流程四步走为了不把概念搞混我把完整流程拆成四个步骤构建评分矩阵把用户对物品的评分整理成行是用户、列是物品的矩阵。计算用户相似度两两计算用户之间的相似度得到一张用户相似度矩阵。选出近邻用户对目标用户来说挑出相似度最高的一批用户作为邻居数量通常用K控制比如Top-10或Top-20。加权预测评分用邻居对目标物品的评分结合相似度作为权重预测目标用户对没接触过的物品的打分最后按预测分数排序推荐。听起来不复杂但第2步和第4步的细节很多人初学时会理解错。我展开讲。3.2 用户相似度到底怎么算计算两个用户之间的相似度常见的有两种思路。余弦相似度把用户对所有物品的评分看成一个向量计算两个向量之间的夹角余弦值。公式是cos(u, v) Σ(r_ui × r_vi) / (√Σ(r_ui²) × √Σ(r_vi²))它的直觉是两个向量方向越一致相似度越高。皮尔逊相关系数它和余弦的区别在于计算前先减掉用户自己的评分均值公式是sim(u, v) Σ(r_ui - r̄_u)(r_vi - r̄_v) / √(Σ(r_ui - r̄_u)² × Σ(r_vi - r̄_v)²)这里r̄_u是用户u的全部已评分物品的均值。为什么要减均值因为不同用户的打分尺度完全不同有的人习惯给高分、一片赞美有的人很严格、能打3分就算不错。减掉均值之后保留的是相对自己习惯的偏离程度这样两个用户之间才有可比性。实践里我见到过不少项目直接用余弦相似度做User-Based CF尤其在隐式反馈场景下。但在显式评分场景皮尔逊通常更稳因为它把用户打分尺度这个系统误差去掉了。第5章我再详细对比。3.3 评分预测别漏掉用户自己的打分尺度找到邻居之后预测目标用户u对物品i的评分最常用的公式是pred(u, i) r̄_u Σ_{v∈N} sim(u, v) × (r_vi - r̄_v) / Σ_{v∈N} |sim(u, v)|这个公式值得仔细拆。它做了三件事第一对邻居的评分减掉邻居自己的均值r_vi - r̄_v把邻居的个人尺度去掉。第二用相似度作为权重邻居越像你贡献越大。第三预测值是在目标用户自己的均值r̄_u上偏移把目标用户的个人尺度加回来。很多人第一次写User-Based CF会犯的错就是简单地用相似度加权邻居的原始评分比如直接算∑ sim * r_vi / ∑ sim。在小规模玩具数据上这样可能也能跑出结果但在真实评分数据上问题很大——如果目标用户习惯给3分而邻居习惯给5分加权出来的分就虚高了。所以说保留这个均值偏移不是锦上添花而是必要操作。3.4 一个小例子手算给你看用第2章那张景点评分表我们来预测用户C对灵隐寺的评分。先算用户B和C的相似度。B和C共同评分过西湖、乌镇、西溪湿地、千岛湖这四个景点数值分别是B(5, 1, 4, 3)C(5, 1, 4, 3)两人的均值都是3.25各自中心化后向量为(0.75, -2.25, 0.75, -0.25)完全一致。所以不管用余弦还是皮尔逊B和C的相似度都等于1是完美正相关。再看用户D和C。D在共同景点上的评分是(2, 4, 2, 1)中心化后为(-0.25, 1.75, -0.25, -1.25)和C的向量方向正好相反算出来的皮尔逊相似度约为-0.66是负相关。如果K2并且我们允许把D也选作邻居那预测公式就会变成pred(C, 灵隐寺) 3.25 [1×(5-3.25) (-0.66)×(4-2.25)] / (1 0.66) ≈ 3.61但如果我们的候选邻居只保留正向相似用户那邻居就只剩B预测结果为pred(C, 灵隐寺) 3.25 1×(5-3.25) / 1 5你看负相关邻居的引入会直接拉低预测分。所以很多实现里会刻意过滤sim 0的邻居或者把K设大一点让单个负相关邻居影响减小。这算是我在代码里踩过的一个实际教训后面第6章我再结合代码说。4. Item-Based CF把矩阵转个方向从物品找邻居Item-Based CF在电商领域用得比User-Based更广你可能听过那句经典的话买了这个商品的用户还买了什么。它就是Item-Based CF的典型应用。它和User-Based用的数学工具几乎一模一样只是把计算的视角从行换到了列。4.1 从用户邻居到物品邻居的视角切换User-Based CF关注的是谁和我像Item-Based CF关注的是什么物品和我喜欢的物品像。它的核心逻辑是如果历史上大量用户都给物品i和物品j打了相近的分数那这两个物品在用户眼中就是相似物品当目标用户喜欢物品i时就可以把物品j推荐给他。这里有个很容易绕进去的坎为什么说物品相似度计算结果不依赖具体某个用户因为物品i和物品j的相似度是通过所有用户对它们两个的评分来算的而不是通过目标用户一个人的偏好。比如灵隐寺和西溪湿地只要大量用户对两者的评分趋同它们就算在目标用户还没有任何评分的情况下也是一个相似对。实现上User-Based矩阵操作可以理解为先对矩阵做转置让列变成行——物品变成用户、用户变成物品——然后套用和User-Based完全一样的相似度计算和预测流程。理解这一点之后很多代码实现会变得非常清爽。4.2 物品相似度的计算细节Item-Based的相似度矩阵在离线阶段就能算好这是它工程上比User-Based更讨喜的重要原因。我们还是用上面的评分表展示灵隐寺和其他景点的相似度。灵隐寺这一列在所有用户上的评分是A2、B5、C0、D4、E2。计算灵隐寺和西湖的普通余弦相似度只保留两个物品都有评分的用户A、B、D、E得到约0.91灵隐寺和西溪湿地的普通余弦相似度约0.93和千岛湖约0.85和乌镇约0.73。如果我按相似度排序灵隐寺最像的景点是西溪湿地然后是西湖。这个结果在直觉上也很合理——去杭州的人通常会同时安排这几个景点它们的评分模式自然就趋同。4.3 修正余弦相似度为什么在Item-Based里更常用我在实际项目中算Item-Based相似度几乎不用普通余弦而是用修正余弦Adjusted Cosine。公式长这样sim(i, j) Σ_u (r_ui - r̄_u)(r_uj - r̄_u) / √(Σ_u (r_ui - r̄_u)² × Σ_u (r_uj - r̄_u)²)注意这里减的还是用户u的评分均值也就是用每个用户自己的评分习惯把分数先校准一遍再算物品之间的相似度。为什么普通余弦在Item-Based里不够好因为不同用户的评分标准差异太大了。比如用户A习惯严打分西湖只给4分、灵隐寺只给2分用户B是个夸夸怪给所有景点都打5分。如果直接用原始分数算余弦B的高分会放大一切会让那些实际口味相距甚远的物品看起来也相似。减去用户均值后我们看的是这个用户比平时更喜欢哪个景点而不是这个用户打了多少分。我做这一行的一个经验是如果你发现相似度矩阵里绝大多数值都偏高比如都超过0.8那大概率就是没有做中心化/均值偏移。这时候别急着调算法先把相似度函数换掉效果往往立竿见影。4.4 Item-Based的预测公式Item-Based CF的预测公式比User-Based简单一些常见两种。一种是纯加权pred(u, i) Σ_{j∈N} sim(i, j) × r_uj / Σ_{j∈N} |sim(i, j)|其中N是目标用户u已经评分过、且和目标物品i相似度最高的K个物品集合。它的逻辑是拿用户对相似物品的打分按相似度加权推测他对新物品的打分。另一种也会加用户均值偏移公式变成pred(u, i) r̄_u Σ_j sim(i, j) × (r_uj - r̄_u) / Σ_j |sim(i, j)|用我们上面的矩阵预测用户C对灵隐寺的评分。C已评分的物品有西湖5、乌镇1、西溪湿地4、千岛湖3。我们取与灵隐寺最相似的两个已评分物品灵隐寺-西溪湿地相似度0.93灵隐寺-西湖相似度0.91。代入纯加权公式pred(C, 灵隐寺) (0.93×4 0.91×5) / (0.93 0.91) ≈ 4.49约等于4.5分。这个结果挺好——C和B口味高度一致B给灵隐寺打了5分而C对西溪湿地和西湖的评分很高Item-Based同样推断出他会喜欢灵隐寺。两种思路殊途同归。5. 相似度公式大乱斗余弦、皮尔逊、修正余弦、Jaccard可能你已经发现了Memory-Based CF最核心的计算都在相似度上。这一章我不再堆叠公式而是把几个相似度指标放到一起对比说清楚各自的脾气和适用场景帮你少走弯路。5.1 四种相似度的公式与直觉余弦相似度本质上衡量的是两个向量的方向一致性。它适合那种关注点是否一致的场景特别是0/1二值数据比如用户有没有点击过某类物品。缺点是对评分尺度敏感一个打2分的用户和一个打5分的用户即便偏好完全相同计算出的余弦也可能偏低。皮尔逊相关系数等价于把两个向量都减去各自的均值后再算余弦所以它相当于中心化后的余弦。它的优点是消除了用户个人评分尺度的影响非常适合显式评分数据缺点是如果共同评分样本太少非常容易算出1或-1这种极端值反而失真。修正余弦相似度它和皮尔逊的核心区别在于减的对象。皮尔逊减的是当前用户的所有评分均值修正余弦在计算物品相似度时对每个用户也减去该用户的所有评分均值但整个运算是在所有共同评分的用户上铺开的。所以在Item-Based场景、尤其评分数据上它基本是首选。Jaccard相似度公式是交集数量除以并集数量只关心两个用户/物品共同出现过的元素完全忽略具体分数。它的优势是计算简单、抗数值噪声适合点击、收藏这类隐式反馈缺点是没法区分很喜欢和一般般的区别。5.2 一张表说清楚怎么选相似度指标适用数据类型是否消除评分尺度偏差主要使用场景余弦相似度数值型、0/1型否隐式反馈、二值点击、特征向量皮尔逊相关系数显式评分是User-Based CF修正余弦相似度显式评分是Item-Based CFJaccard相似度0/1型不涉及隐式反馈、行为交集判断这张表大家可以收藏。我每次给新项目做方案时基本就是按着这个思路选的先确认手里是显式评分还是隐式行为再决定用哪个相似度然后去算相似度矩阵。5.3 共同评分数量被忽略的信任因子这里要单独提醒一个很隐蔽的坑相似度公式本身不会告诉你这个相似度可信不可信。两个用户只有一个共同评分且恰好都打了5分皮尔逊算出来是1两个用户有200个共同评分算出来是0.9。从数值上看前者比后者还高但显然200个共同评分算出的0.9更可靠。我常用的补救方法是给相似度加一个显著性加权sim_final(u, v) sim_raw(u, v) × min(1, common_count / α)其中α是个阈值通常取25到50之间。共同评分数量超过α的权重是1完全保留不足α的按比例打折。这个技巧在数据量小的冷启动阶段特别有效能显著减少偶然相似带来的误推。6. 用Python从零实现一套最小可用CF理论讲再多不如对着代码跑一遍。这一章我用Python手写一个最小可用的Memory-Based CF不依赖任何推荐系统框架只用到Pandas和NumPy。6.1 数据准备构造一个能跑通的小数据集我把第2章的评分表直接写成DataFrame方便复现import pandas as pd import numpy as np R pd.DataFrame({ 西湖: [4, 5, 5, 2, 1], 灵隐寺: [2, 5, 0, 4, 2], 乌镇: [3, 1, 1, 4, 5], 西溪湿地: [3, 4, 4, 2, 1], 千岛湖: [4, 3, 3, 1, 2] }, index[A, B, C, D, E]) print(R)输出就是前面那张评分矩阵。0表示用户没有评分。6.2 User-Based实现与预测过程先实现皮尔逊相似度只考虑两个用户共同评分过的物品def user_pearson(u, v): common [item for item in R.columns if R.loc[u, item] 0 and R.loc[v, item] 0] if len(common) 2: return 0.0 ru R.loc[u, common] rv R.loc[v, common] ru_centered ru - ru.mean() rv_centered rv - rv.mean() denom np.sqrt((ru_centered ** 2).sum() * (rv_centered ** 2).sum()) if denom 0: return 0.0 return (ru_centered * rv_centered).sum() / denom再写预测函数。有一个关键点邻居只保留相似度大于0的用户同时用均值偏移做校准def predict_user_based(u, item, k2): ru_bar R.loc[u, R.loc[u] 0].mean() candidates [] for v in R.index: if v u: continue if R.loc[v, item] 0: continue sim user_pearson(u, v) if sim 0: rv_bar R.loc[v, R.loc[v] 0].mean() candidates.append((v, sim, R.loc[v, item], rv_bar)) candidates.sort(keylambda x: x[1], reverseTrue) top candidates[:k] if not top: return ru_bar num sum(sim * (rating - rv_bar) for _, sim, rating, rv_bar in top) den sum(abs(sim) for _, sim, _, _ in top) return ru_bar num / den print(predict_user_based(C, 灵隐寺, k2))按前面手算的逻辑B和C的相似度为1E和C的相似度是负值、会被过滤掉所以预测值输出约为5.0。这跟手工计算一致。6.3 Item-Based实现与预测过程Item-Based的代码和User-Based有点像但计算对象变成了物品列。这里我用余弦相似度代码更直观实际工程中你把它换成修正余弦即可def item_cosine(i, j): common [u for u in R.index if R.loc[u, i] 0 and R.loc[u, j] 0] if len(common) 2: return 0.0 ri R.loc[common, i] rj R.loc[common, j] denom np.sqrt((ri ** 2).sum() * (rj ** 2).sum()) if denom 0: return 0.0 return (ri * rj).sum() / denom def predict_item_based(u, item, k2): rated_items [j for j in R.columns if j ! item and R.loc[u, j] 0] candidates [] for j in rated_items: sim item_cosine(item, j) if sim 0: candidates.append((j, sim, R.loc[u, j])) candidates.sort(keylambda x: x[1], reverseTrue) top candidates[:k] if not top: return 0.0 num sum(sim * rating for _, sim, rating in top) den sum(abs(sim) for _, sim, _ in top) return num / den print(predict_item_based(C, 灵隐寺, k2))前面手算过与灵隐寺最相似的两个已评分物品是西溪湿地和西湖预测输出约为4.49。6.4 两种方法预测同一个评分的差异分析同一个问题User-Based给出5.0Item-Based给出4.49出现了差异这是为什么User-Based的预测路径是找相似用户。因为B和C的评分几乎完全一致B给灵隐寺打了5分所以结果接近5。Item-Based的路径是找相似物品。C给西溪湿地和西湖打了高分而这两个物品和灵隐寺相似所以加权出大约4.5。路径不同结果自然不同。这个差异在真实项目里其实是好事。如果你在线上同时跑两套模型用户刚点过和某个物品相似的另一个物品时Item-Based会更灵敏当存在一个口味极其相似的用户群体时User-Based会更灵敏。很多团队会把两者结果做加权融合或者用其中一方做召回、另一方做排序特征效果往往比只用一套好。7. 工程落地时会踩的坑稀疏、冷启动、热门偏差把代码跑通只是万里长征第一步。到了真实业务数据上Memory-Based CF会遇到几个很顽固的问题我在项目里一个个踩过拿出来说透。7.1 无共同评分相似度直接失灵真实评分矩阵非常稀疏两个用户之间可能一个共同评分都没有。这时候User-Based的相似度矩阵就像个漏勺——大量用户之间的相似度是0根本形成不了信任链。这事的本质原因是评分是用户主动产生的成本太高绝大多数用户只对极小一部分物品留下过痕迹。应对思路我常用两种把评分矩阵从显式评分扩展到隐式行为数据。比如用户在景点详情页的停留时长、点击次数这些数据密度高很多能补上相似度空洞。用基于内容的相似度做补充。比如两个景点都属于人文历史类即使没有共同评分也可以给一个初始相似度等后续交互数据积累后再逐渐让位于协同过滤。7.2 热门物品绑架了相似度假设西湖是这个旅游推荐系统里最热门的景点80%的用户都评过分。那么计算任意两个用户相似度时西湖几乎总是落在共同评分里它的评分贡献会盖过其他小众景点。结果是两个口味完全不同的人仅仅因为都给西湖打了分可能就会算出很高的相似度。这是热门偏差。解决办法是给物品加权降低热门物品的影响力。常用的一个技巧叫IUFInverse User Frequency类比TF-IDF的思路w_i 1 / log(1 n_i)其中n_i是给物品i评过分的用户数。把评分r_ui乘以这个权重后再去算相似度热门物品因为权重小就不会再主导相似度计算了。还有个更简单粗暴的办法在计算相似度时如果共同评分里包含热门物品可以直接给它设一个很小的全局权重。我在很多小项目里都是这么干的效果稳定又不用引入太多参数。7.3 冷启动不止新用户还有新物品冷启动分两种。新用户没有历史评分Memory-Based CF找不到他的邻居也无法通过他已评物品做Item-Based推荐新物品没有用户评分它不会出现在任何人的相似物品集合里自然也就无法被推荐出去。处理新用户我通常先给一个基于热度的兜底推荐比如热门景点榜等用户产生几条交互后再用协同过滤处理新物品则要靠内容特征来搭桥比如新上架一个景点先用它的地理位置、类型标签、价格区间去找内容上相似的旧物品把相似度先算出来这样等有了评分后模型已经能推了。7.4 离线预计算相似度矩阵才是工程常态Memory-Based这个名字很容易让人误以为每次来了推荐请求都要现场把所有用户/物品相似度算一遍。如果真这么做线上延迟会爆炸。工程上的标准做法是把相似度计算这个重活放到离线定时用Spark或者普通Python批处理任务算好用户相似度矩阵或物品相似度矩阵存储到Redis、内存KV存储或者向量数据库里。线上推荐时只需要拿到目标用户/目标物品去查它的Top-K邻居然后做一次轻量加权计算。整个过程毫秒级就能完成。订单相关项目里我会再设置一个增量更新任务比如每15分钟或每小时把新增的交互记录并入重新计算受影响的那部分相似度。全量重算的成本太高没必要每次跑。把这个流程想清楚Memory-Based CF就具备了支撑日活百万级业务的能力。8. User-Based还是Item-Based一张决策清单学完两种算法实践中总会有一个绕不开的问题该用哪个8.1 关键维度对比维度User-Based CFItem-Based CF核心视角找相似用户找相似物品计算规模用户数越多矩阵越大物品数越多矩阵越大可解释性和你有相同口味的人还喜欢…因为你喜欢X所以推荐相似的Y实时性对用户新行为敏感能快速跟进口味变化对物品上新更敏感用户行为变化反映稍慢冷启动压力新用户问题突出新物品问题突出长尾推荐相对容易发现小众新物品容易集中推荐热门相似物品适用场景社交、资讯、用户群体特征明显的领域电商、内容社区、酒旅、景点8.2 我选择时的经验原则我不喜欢记死规则但下面几条原则是经过几个项目验证过的可以帮你快速做决策看用户数和物品数的相对规模。用户数远大于物品数推荐用Item-Based因为物品相似度矩阵小、计算快、且物品实体相对稳定。旅游推荐系统里景点数量往往远小于用户量所以Item-Based天然合适。反过来如果物品数量庞大且更新极快比如新闻信息流User-Based可能更灵活因为它能通过用户的邻居快速把新物品传给目标用户。看重可解释性的业务优先Item-Based。因为你喜欢乌镇所以推荐西塘比因为和你类似的游客喜欢西塘更容易让用户接受。小数据起步阶段两套都跑取并集做召回。再多说一句很多时候你不必在User-Based和Item-Based之间二选一把两者的推荐结果合并作为召回池再让排序模型去打分是工业界非常常见的做法。8.3 笔记之外的结束语最后分享一点个人习惯。我不管后续要用多复杂的模型接手一个新推荐项目的第一天一定先写一套Item-Based CF跑出基线同时配一套User-Based CF做对比。不是因为它们能直接达到最好的效果而是因为它们是整个推荐系统领域最透明的镜子——如果连这面镜子都跑不出合理结果说明数据质量或者相似度选择一定有问题这时候去调深度学习模型纯粹是浪费时间。另外有个小技巧想送给你实际业务里相似度矩阵结果一定要定期人工抽检。我遇到过很多次模型离线指标涨了但线上推荐的结果莫名其妙查到最后都是相似度矩阵里出现了西湖和千岛湖相似度接近1这种反直觉数据。数据清洗、评分归一化、去热门这些基础工作比选一个高级模型更影响最终体验。先把Memory-Based CF这层地基打牢再往上盖模型你会少走很多弯路。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。