想象你身边那位“最懂吃”的朋友。你只说一句“上次那家川菜馆的毛血旺绝了”,他立马接住话茬:“那你一定喜欢花椒味重、料足、价格还实惠的店,走,我带你去城西那家江湖菜。”他当然不是神算子——他只是把每一道你爱吃的菜,都拆解成一串可以量化的属性:重麻、重辣、分量足、性价比高,然后再把整座城市餐厅的招牌菜,同样拆解成一张张“属性身份证”,逐一和你的偏好比对。哪张身份证和你的口味最“合拍”,哪道菜就被端上你的餐桌。 这就是基于内容的推荐(Content-Based Recommendation,简称 CB)。它不关心“别人点什么菜”,只关心“菜本身是什么”和“你爱吃什么”。每一件物品都可以被拆解成标签、关键词、特征向量;每一位用户都可以被刻画成一张偏好清单;推荐,就是这两者之间的一次“缘分计算”。 在真实的互联网世界里,CB 是新闻、资讯、图文类平台最倚重的推荐手段。新文章刚发布、没有任何人看过,平台照样能靠它“听懂”内容、匹配给你——就像老友面对从未谋面的新朋友,一句“你吃辣吗”就能开启推荐。这正是 CB 被称为冷启动利器的原因。 这篇文章,我们就化身这位吃货老友,从拆解一道菜开始,完整走一遍 CB 的思考流程:如何提取内容特征、如何构建用户画像、如何计算相似度、如何与协同过滤融合,以及如何把这一整套搬到线上工程里。

岗位关联

学会 CB 是进入推荐系统领域的第一块敲门砖——它是冷启动问题的头号解药,也是新闻、图文、电商场景最经典的推荐基线。掌握它的特征提取、画像构建与相似度打分链路,你就能读懂绝大多数推荐系统的底层逻辑。

目录
  1. 可视化演示
  2. 核心思想:点菜先拆菜,不看邻桌
  3. 特征提取:给每道菜办一张“身份证”
  4. 用户画像:老友随身带的小本本
  5. 相似度计算:用余弦算“口味缘分”
  6. 冷启动场景:新客人也有推荐
  7. 混合推荐:既懂你又懂大众
  8. 工程落地:从手写小本本到中央厨房
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

TF-IDF特征提取 TF: 词频统计衡量词语重要性 IDF: 逆文档频率降低常见词权重 TF-IDF = TF × IDF 提取物品内容特征向量

核心思想:点菜先拆菜,不看邻桌

老友给你推荐的第一原则是这样的:“我对你还没那么了解不要紧,先看看你上次夸过的那道菜,把它拆开看看。”他会说——“你喜欢毛血旺,那就是重麻、料多、便宜。你根本不用告诉我你整个人的来龙去脉,我只要把这道菜拆明白,就拿到了你半张口味地图。”这就是 CB 的第一性原理:推荐依据来自物品本身的属性,而不是其他食客的集体选择。

技术世界里,CB 把这条原则翻译成三块积木:物品画像(Item Profile)——用特征描述每个物品“长什么样”;用户画像(User Profile)——用特征描述你“喜欢什么”;匹配打分(Scoring)——把两者放在同一套坐标系里算相似度。得分最高的物品,进入推荐列表。整个流程可以浓缩成一条“缘分公式”。

这条公式背后是标准的 CB 推理链路:平台先把你的历史行为凝固成一个偏好向量,再把候选池里每篇内容编码成同维度的特征向量,然后用相似度函数批量打分、排序、截取 TopN。它不关心别的用户点了什么,所以解释推荐理由时可以说得很直白:“因为这篇讲大模型,而你点过很多篇大模型文章。”

老友这一套“拆菜–记口味–算缘分”的打法好处显而易见:推荐理由能讲明白、新用户也能上手。但他也有死穴——只盯着你吃过的菜,就永远不敢带你去尝试甜点和异国料理。这为后文埋下伏笔:CB 守正,CF 出奇,两者融合才是完整的一桌菜。

Score(u,d)=Sim(u⃗profile, v⃗content)\displaystyle \mathrm{Score}(u, d) = \mathrm{Sim}\Big(\vec{u}_{\text{profile}},\ \vec{v}_{\text{content}}\Big)
这条公式的意思是:给用户 $u$ 推荐物品 $d$ 的分数,等于“用户偏好向量”和“物品内容向量”之间算出来的一次相似度。
  1. 用户偏好向量把“你爱吃什么”量化成一个多维向量,每个维度对应一个属性,比如“麻辣”维度权重 0.9、“实惠”维度权重 0.7。这一步对应老友小本本上你的口味记录。
    u⃗profile=(0.9, 0.7, 0.6, 0.8)\vec{u}_{\text{profile}} = (0.9,\ 0.7,\ 0.6,\ 0.8)
  2. 内容特征向量把物品 $d$ 的属性同样编码成相同维度的向量。一道川味火锅的向量可能是 $(0.9, 0.5, 0.8, 0.7)$,它和你的画像几乎重叠,分数自然就高。
    v⃗content(d)=(v1, v2, …, vn)\vec{v}_{\text{content}}(d) = (v_1,\ v_2,\ \dots,\ v_n)
  3. 相似度函数它是“缘分计算器”,最常用的是余弦相似度——只管两个向量的方向是否一致,越同向越有缘。后端拿到打分后,按从高到低输出 TopN 推荐池。
    Sim(a⃗,b⃗)∈[−1, 1]\mathrm{Sim}(\vec{a},\vec{b}) \in [-1,\ 1]

特征提取:给每道菜办一张“身份证”

老友要在一座城市的上千道菜里帮你找“下一个最爱”,总不能靠舌头一道一道试。他先给每道菜办了一张“身份证”:辣度、主食材、烹饪方式、人均价格、分量等级——每个项目都填上 1 到 10 的刻度值。有了这张卡,他不用尝,就能把“重庆小面”和“酸辣粉”归到同一类“麻辣系”里。

在 CB 系统里,这张“身份证”叫物品画像(Item Profile),它的填写方式取决于内容类型:结构化标签最直接,人工或规则打上“麻辣”“下饭”等分类;文本内容则用 TF-IDF 把标题正文转成数值向量;封面图可以用预训练视觉模型抽取特征;数值属性如价格、时长则要做归一化,避免“价格”这种大数把“辣度”这种小数压制住。

文本是新闻资讯的主战场,TF-IDF 是这里的地基。它回答两个问题:这个词在本文里出现得多不多(TF),这个词在全库里是不是足够稀有(IDF)。常见词“的”“了”的 IDF 趋近于 0,会被自动降权;“大模型”“冷启动”这类词则获得高权重,因为它们能真正区分文章主题。

有了身份证,老友的评价就不再是感性的“好吃”,而是“辣度 9/10、人均 60、分量 8/10”这样可比较、可排序、可检索的数据。物品特征越规范,后端的相似度计算就越扎实。这也是为什么 CB 系统上线前的第一件事,永远是打磨特征提取管线——它决定了整条推荐链能站多稳。

TF-IDF(t, d)  =  TF(t,d)×IDF(t)  =  nt,d∑knk,d×log⁡N dft \displaystyle \mathrm{TF\text{-}IDF}(t,\,d) \;=\; \mathrm{TF}(t,d)\times \mathrm{IDF}(t) \;=\; \frac{n_{t,d}}{\sum_{k} n_{k,d}} \times \log\frac{N}{\,df_t\,}
TF 管“这个词在本文重不重要”,IDF 管“这个词在全库稀不稀有”,两者相乘就是一词对这篇文章的“身份贡献值”。
  1. TF 词频$n_{t,d}$ 是词 $t$ 在文档 $d$ 中出现的次数,$\sum_k n_{k,d}$ 是文档 $d$ 的总词数。两者相除得到词频占比——“大模型”在一篇 500 字的文章里出现 10 次,TF 就是 0.02,说明它反复出现、很可能是主题词。
    TF(t,d)=nt,d∑knk,d\mathrm{TF}(t,d)=\frac{n_{t,d}}{\sum_{k} n_{k,d}}
  2. IDF 逆文档频率$N$ 是语料库文档总数,$df_t$ 是包含词 $t$ 的文档数。$df_t$ 越小,$\log(N / df_t)$ 越大——“的”几乎每篇都有,IDF 接近 0;“仿生机器人”几万篇才出现一次,IDF 就很大。
    IDF(t)=log⁡Ndft\mathrm{IDF}(t)=\log\frac{N}{df_t}
  3. 相乘得权重把 TF 和 IDF 相乘,每个词的权重既反映它在本文的地位,又滤掉全库通用的“废话词”。最终每一篇文档都变成一个稀疏的高维向量,这就是它的“内容身份证号”。
    wt,d=nt,d∑knk,d×log⁡Ndftw_{t,d} = \frac{n_{t,d}}{\sum_k n_{k,d}} \times \log\frac{N}{df_t}

用户画像:老友随身带的小本本

老友的口袋里永远有一本皱巴巴的小本本。每当你对一道菜点头——“这个麻得舒服!”——他就在这道菜的“身份证副本”上画一颗星;如果你把筷子一放,他就画一道杠。星星和杠越来越多,他翻到某一页,把每个维度的分值加总再一平均,你的口味画像就成了。

在系统里,这本小本本叫用户画像(User Profile)。构建过程分三步:先收集你的历史行为(曝光、点击、收藏、分享、付费),再把行为对象的特征向量按反馈强度加权累加,最后归一化得到你的偏好向量。正反馈加深色,负反馈减淡色,这和本本上画星画杠是同一个道理。

具体来说,假设你把某篇“大模型科普”收藏了(权重 3),把另一篇“猫咪视频”划走了(权重 0),画像里“科技”维度的分量就会显著高于“萌宠”。权重设计很关键:点了一下可能是误触,收藏说明心动,付费才是真爱——不同行为要把“喜欢程度”翻译成不同数值。

这本小本本不是一次成型的。今天你连刷十篇大模型文章,明天画像里“科技”维度就蹿高;月底你只想看美食,画像又悄悄转向。所以工程上用户画像要走“增量更新 + 时间衰减”,让最近的兴趣更有话语权——毕竟老友也会定期把本本上盖满灰的旧口味页撕掉。

u⃗u  =  ∑d∈Huru,d⋅v⃗d∑d∈Huru,d\displaystyle \vec{u}_{u} \;=\; \frac{\sum_{d \in H_u} r_{u,d} \cdot \vec{v}_{d}}{\sum_{d \in H_u} r_{u,d}}
这段公式说的是:你的偏好向量,等于“你碰过的所有物品的特征向量,按你反馈的强烈程度做加权平均”。
  1. 历史行为集合用户 $u$ 点击、收藏、购买过的物品集合。它是画像的原材料——没有行为就没有画像,这也是新用户需要冷启动引导的原因。
    Hu={d1, d2, …, dm}H_u = \{ d_1,\ d_2,\ \dots,\ d_m \}
  2. 行为权重不同行为代表不同强度的“喜欢”。点了一下可能是路过,收藏了说明心动,付费了才是真爱。给不同行为赋不同权重,画像才不会被误点带偏。
    ru,d={1点击3收藏5付费r_{u,d} = \begin{cases} 1 & \text{点击} \\ 3 & \text{收藏} \\ 5 & \text{付费} \end{cases}
  3. 加权累加并归一化分子把物品向量按权重加总,分母把权重加总。相除之后得到一个长度合理的偏好向量——它不再属于任何一篇具体文章,而是“像你一样读文章的那个虚拟读者”。
    u⃗u=∑d∈Huru,d⋅v⃗d∑d∈Huru,d\vec{u}_{u} = \frac{\sum_{d \in H_u} r_{u,d} \cdot \vec{v}_{d}}{\sum_{d \in H_u} r_{u,d}}

相似度计算:用余弦算“口味缘分”

画像有了、菜的身份卡也有了,接下来就差最后一步——把两者放在桌上比一比。老友用的办法很朴素:把两个向量的起点钉在同一个原点,看它们的夹角。夹角几乎为零,说明方向和你的口味完全一致,缘分 100%;夹角接近 90°,说明两股道上的车,别强求。这个“夹角余弦值”,就是数学版的缘分指数。

机器学习里,衡量两个向量相似度最经典的工具就是余弦相似度(Cosine Similarity)。它的好处是只关心方向、不关心长度——你本子上星画得多不多(向量模长)不影响“菜品和你的口味同不同向”。另一个常用工具是点积(内积),它同时考虑方向和强度,计算更快,适合工程上做近似召回。

在 CB 打分阶段,系统会对候选池里每一篇内容都算一遍余弦相似度,然后从高到低排序。这也是为什么特征向量必须先归一化:如果有的维度取值 0 到 1、有的维度取值 0 到 10 万,那么“价格”这一个维度就会淹没“辣度”等所有其他维度,算出来的相似度全是价格的形状。

老友用铅笔在桌面上画来画去,其实就是在心算余弦。夹角小、方向一致,他就敢拍胸脯带你进店;夹角大,他就劝你“这家风格不对路”。不过他也清楚,单靠一个向量不可能覆盖你完整的味蕾——人的兴趣会漂移,所以后面的工程环节他会不断翻新小本本。

cos⁡θ  =  u⃗⋅v⃗∥u⃗∥⋅∥v⃗∥  =  ∑i=1nui vi∑i=1nui2×∑i=1nvi2\displaystyle \cos\theta \;=\; \frac{\vec{u}\cdot\vec{v}}{\lVert \vec{u}\rVert \cdot \lVert \vec{v}\rVert} \;=\; \frac{\sum_{i=1}^{n} u_i\, v_i}{\sqrt{\sum_{i=1}^{n} u_i^{2}}\times \sqrt{\sum_{i=1}^{n} v_i^{2}}}
公式把“两个向量的夹角余弦”拆成了“点积除以两个模长之积”——只保留方向信息,抹掉长度差异。
  1. 向量点积把用户画像和物品特征在每一个维度上相乘再求和。维度方向一致(都是高分),乘积就大;方向相反,乘积是负的,说明口味对着干。
    u⃗⋅v⃗=∑i=1nui vi\vec{u}\cdot\vec{v} = \sum_{i=1}^{n} u_i\, v_i
  2. 模长归一化对每个向量各维平方求和再开根号,得到“长度”。除以两个长度,等于把两个向量都缩放到单位长度,消除“用户特别热情、所有维度都 0.9,而菜品所有维度都是 0.5”这类整体幅度差异。
    ∥a⃗∥=∑i=1nai2\lVert \vec{a}\rVert = \sqrt{\sum_{i=1}^{n} a_i^{2}}
  3. 比值即为相似度结果落在 $[-1,1]$,CB 场景特征非负时落在 $[0,1]$,越接近 1 代表口味越合拍。全量候选池算完一轮后,按分数从大到小排序截取 TopN,就形成推荐列表。
    TopN=argsort(cos⁡θ1, cos⁡θ2, …)[:N]\mathrm{TopN} = \mathrm{argsort}\big(\cos\theta_1,\ \cos\theta_2,\ \dots\big)[:N]

冷启动场景:新客人也有推荐

老友最得意的一招,是面对刚落座、还互不熟悉的新朋友,也能立刻开口:“我猜你爱重口味——你点菜上来就问有没有辣,对吗?”他不需要观察你三个月,只需要你勾几个标签、答三五个问题,就能拼出一张粗略的画像,先推一轮再说。

这就是 CB 在推荐系统领域最闪耀的名场面——冷启动(Cold Start)。协同过滤见到新用户束手无策,因为“没有行为可以聚类”;CB 却完全不在乎:新用户的画像可以来自注册时的兴趣标签勾选(“我喜欢科技、健身、财经”),可以来自兴趣问卷(五道题摸清偏好),也可以来自一两篇点赞的文章。物品端同理:一篇新文章发布的那一刻就有标题和正文,TF-IDF 向量当场生成,立刻进入候选池。

在真实的新闻平台里,每天有成千上万篇新文章涌入,它们没有点击、没有收藏、没有任何群体行为数据。如果系统只有协同过滤,这些文章会石沉大海;而 CB 的冷启动打分公式极其轻量——画像向量点乘新文章的内容向量,一步到位。

对新闻资讯类平台,这种“发布即推荐”的能力等于生产力:编辑刚按下发布键,文章就开始被匹配给最可能点开的人群。老友在新朋友面前赢得信任,靠的也是这一手“先猜后证”——猜错了再调整,猜对了就多了个铁杆吃货。

Scorecold(u, p)  =  u⃗profile⋅v⃗content(p)\displaystyle \mathrm{Score}_{\text{cold}}(u,\,p) \;=\; \vec{u}_{\text{profile}} \cdot \vec{v}_{\text{content}}(p)
这是冷启动专用的“轻量打分”:一次点积,新物品也能立即参与竞争推荐位。
  1. 新物品内容向量文章发布瞬间,系统用 TF-IDF 或标签体系为它生成内容向量。这是 CB 冷启动的底气——特征不依赖任何用户行为,天生自带。
    v⃗content(p)=(wt1, wt2, …)\vec{v}_{\text{content}}(p) = \big(w_{t_1},\ w_{t_2},\ \dots\big)
  2. 与画像点积把新内容的向量和用户画像做点积。因为两者同维度、同语义空间,乘积越大说明这篇新文章越贴合你的历史兴趣。
    Scorecold=∑iui⋅wti\mathrm{Score}_{\text{cold}} = \sum_{i} u_i \cdot w_{t_i}
  3. 参与排序竞争点积分和常规候选的分数放进同一个榜单里排序,新文章就有了和热门老文章同台竞技的机会。
    Final(p)=Rank(Score(u,p))\mathrm{Final}(p) = \mathrm{Rank}\big(\mathrm{Score}(u,p)\big)

混合推荐:既懂你又懂大众

老友也有翻车的时候:他太懂你的老口味,于是只敢推老味道,带你去的新店永远是“麻辣系的另一家”。直到有一天他学会了一招——点菜前偷偷看一眼大众点评,把“你爱吃的”和“大家都说好的”各按一半权重综合起来。从此,他既能守住你的口味,又能带你解锁全城最火的新店。

技术世界同样如此。CB 太“守正”,容易把用户困在信息茧房里,推荐的永远是相似内容;CF 太“出奇”,依赖群体行为,冷启动和长尾内容乏力。于是工业界普遍采用混合推荐(Hybrid Recommendation):最常见的是加权融合——CB 和 CF 各算各的分,最后按一个可调系数 $\alpha$ 线性叠加。

这个 $\alpha$ 不是拍脑袋定的。新用户行为稀疏,CF 分数不可信,$\alpha$ 偏向 1、以 CB 为主;老用户行为丰富,$\alpha$ 可以降到 0.5 左右,让 CF 带来更多意外之喜。线上通常跑 A/B 实验:一半用户用 $\alpha=0.6$,另一半用 $\alpha=0.7$,看哪个组合的点击率更高,再全量上线。

现在老友的推荐话术升级成了:“这家川菜够麻,符合你的画像;而且最近全城都在排它,大众点评 4.9 分。”一个是你的私人喜好,一个是群体的集体智慧,两票并作一票,推荐自然更经得起实战考验。这也就是工业界那句老话——推荐系统没有银弹,混合才是常态。

Scorehybrid(u,d)  =  α⋅ScoreCB(u,d)  +  (1−α)⋅ScoreCF(u,d)\displaystyle \mathrm{Score}_{\text{hybrid}}(u,d) \;=\; \alpha\cdot \mathrm{Score}_{\text{CB}}(u,d) \;+\; (1-\alpha)\cdot \mathrm{Score}_{\text{CF}}(u,d)
$\alpha$ 是“重心旋钮”:偏向 1 就是纯 CB,偏向 0 就是纯 CF,中间值按下线阶段的目标来调。
  1. CB 得分基于内容相似度,由画像向量与物品向量做余弦得到,对新物品友好、可解释性强。
    ScoreCB=cos⁡(u⃗profile, v⃗content)\mathrm{Score}_{\text{CB}} = \cos(\vec{u}_{\text{profile}},\ \vec{v}_{\text{content}})
  2. CF 得分基于“与你相似的用户看了什么”,由协同过滤模型给分,能带来跨类别惊喜,但冷启动阶段无分可用。
    ScoreCF=ItemCF / MF 预测分\mathrm{Score}_{\text{CF}} = \text{ItemCF / MF 预测分}
  3. 加权融合与调优$\alpha \in [0,1]$ 是核心超参数,通常用 A/B 实验选优——把“所有用户用同一个 $\alpha$”改成“分组对照”,用点击率等指标做决策。
    α∗=arg⁡max⁡α CTR(hybridα)\alpha^{*} = \arg\max_{\alpha} \ \text{CTR}\big(\text{hybrid}_{\alpha}\big)

工程落地:从手写小本本到中央厨房

老友的小本本,服务三五个朋友绰绰有余;若餐厅要同时服务十万个食客,手写记录就彻底失灵了。于是老友把笔记搬进“中央厨房”:所有菜的身份证统一放在一个巨大的档案柜里,每个客人本本上的新笔记由前台服务员实时誊抄,到点再由总厨统一对表、批量出菜。

CB 工程化牵涉三块:离线计算、实时更新、特征存储。物品画像和文本向量可以离线批量算好,因为文章一天更新几千篇而非每秒几万条;用户画像则要准实时增量更新——用户点了一条新闻,几秒内他的画像就应反映这个变化,否则推荐永远慢半拍。

增量更新画像的经典写法是带时间衰减的滑动加权:每次新行为把旧画像乘以一个衰减系数 $\gamma$(如 0.95,越接近 1 越念旧),再加上新行为的特征增量。特征存储上,结构化标签放 Redis 或 MySQL,文本向量放向量数据库(如 FAISS、Milvus),检索时用近邻搜索代替全量遍历,把耗时的余弦计算变成毫秒级召回。

至此,老友的“中央厨房”完全成型:档案柜里躺着离线算好的物品画像,前台不断誊抄新口味笔记,后厨按相似度打分出餐,每周做一轮 A/B 实验微调菜谱。CB 从一句“你爱吃什么”开始,最终变成一套能服务千万级用户、毫秒级出结果的工业系统。

u⃗u(t+1)  =  γ⋅u⃗u(t)  +  ηu,d⋅v⃗d\displaystyle \vec{u}_u^{(t+1)} \;=\; \gamma \cdot \vec{u}_u^{(t)} \;+\; \eta_{u,d}\cdot \vec{v}_d
这条递推公式是“画像的呼吸节奏”:旧偏好被乘以衰减系数慢慢淡出,新行为以一定学习率融入,既跟得上热点又不会忘记根基。
  1. 旧画像向量截至当前时刻 $t$ 的用户偏好向量,是历史所有行为的加权沉淀。
    u⃗u(t)=(u1(t), u2(t), …, un(t))\vec{u}_u^{(t)} = (u_1^{(t)},\ u_2^{(t)},\ \dots,\ u_n^{(t)})
  2. 衰减系数旧画像每次更新乘以 $\gamma \in (0,1)$。若一直不产生新行为,画像分量随时间指数衰减;$\gamma$ 越大,用户兴趣衰减越慢,越“念旧”。
    lim⁡t→∞γt=0\lim_{t\to\infty} \gamma^{t} = 0
  3. 新行为增量$\eta_{u,d}$ 是本次行为的权重(如收藏大于点击),$\vec{v}_d$ 是被行为物品的特征向量。两者相乘作为本次更新加进画像的“新菜料”。
    Δu⃗=ηu,d⋅v⃗d\Delta \vec{u} = \eta_{u,d}\cdot \vec{v}_d

AI 应用场景

新闻资讯平台的“发布即推荐”

阶段:召回与冷启动

解决的问题:传统新闻推荐依赖协同过滤,新文章没有点击数据就进不了推荐池,导致编辑的心血被埋没。CB 在文章发布瞬间提取标题和正文的 TF-IDF 特征,与用户画像做余弦匹配,新文章立即进入推荐队列,从“发完慢慢推”变成“发完即刻推”。

具体案例:某新闻 App 接入 CB 冷启动管线后,新文章进入推荐池的等待时间从平均 2 小时缩短到 3 分钟,新文章曝光量提升 40%。典型链路:编辑发布 → 内容特征提取 → 向量写入 FAISS → 召回阶段按余弦相似度取 TopN → 与 CF 结果混合重排。

电商“看了又看”相似商品推荐

阶段:相关性召回

解决的问题:用户在商品详情页停留时,需要即时推荐“和当前商品相似的其他款”。传统做法靠人工运营配置关联,时效差、覆盖少。CB 把商品的价格、类目、品牌、视觉特征编码成向量,与用户画像结合打分,给出“风格相近、价位相当”的候选。

具体案例:淘宝、京东的“找相似”本质上是一种以当前物品为锚点的 CB:以图片向量做视觉相似,以类目标签做结构相似,以价格区间做约束,三者加权召回,让用户“逛着逛着就下单”。

用户注册时的兴趣引导

阶段:新用户冷启动

解决的问题:全新用户没有任何行为,CF 无法工作,第一屏推荐全凭运气,新用户极易流失。CB 平台引导用户勾选兴趣标签(健身、美食、科技)或回答问卷,这些标签直接被转换成初始用户画像,配上 CB 立刻生成第一屏推荐,显著提升次日留存。

具体案例:主流资讯和短视频 App 的注册页都会让新用户选择 3 到 5 个感兴趣的分类,后端把分类映射成画像权重,第一屏推荐即由 CB 输出。用户点掉几条内容后,画像再逐步切换成“行为驱动”模式。

Python 演示

python54 行
import mathfrom collections import Counter # 小型新闻池:每篇新闻只有 id、标题简写、内容标签NEWS_POOL = [    {"id": 0, "title": "Apple launches AI phone", "tags": ["tech", "apple", "ai"]},    {"id": 1, "title": "LLM breaks new record", "tags": ["tech", "ai", "research"]},    {"id": 2, "title": "Sichuan food guide", "tags": ["food", "life", "travel"]},    {"id": 3, "title": "EV sales hit peak", "tags": ["car", "tech", "market"]},    {"id": 4, "title": "Weekend hiking routes", "tags": ["life", "sport", "travel"]},] USER_HISTORY = [0, 1]  # 假设用户点过 id 0 和 id 1 两篇科技新闻  def build_user_profile(history, pool):    """第 1 步:用历史点击文章的标签构建用户画像(特征加权累加再归一化)"""    profile = Counter()    for hid in history:        profile.update(pool[hid]["tags"])    total = sum(profile.values())    for key in profile:        profile[key] /= total    return profile  def cosine_sim(profile, doc_tags):    """第 2 步:计算用户画像与候选文章特征向量的余弦相似度"""    doc_vec = Counter(doc_tags)    common = set(profile) & set(doc_vec)    dot = sum(profile[k] * doc_vec[k] for k in common)    norm_u = math.sqrt(sum(v * v for v in profile.values()))    norm_d = math.sqrt(sum(v * v for v in doc_vec.values()))    return dot / (norm_u * norm_d + 1e-9)  def recommend(profile, pool, history, top_n=3):    """第 3 步:对候选池打分排序,过滤已看过的文章,返回 TopN"""    scored = []    for doc in pool:        if doc["id"] in history:            continue        score = cosine_sim(profile, doc["tags"])        scored.append((doc, score))    scored.sort(key=lambda x: x[1], reverse=True)    return scored[:top_n]  if __name__ == "__main__":    profile = build_user_profile(USER_HISTORY, NEWS_POOL)    print("用户画像(标签->权重):", dict(profile))    print("基于内容的推荐结果:")    for doc, score in recommend(profile, NEWS_POOL, USER_HISTORY):        print(" - %s, 匹配度 %.2f" % (doc["title"], score))
目的:用 20 行核心逻辑演示 CB 三大步——从历史点击构建用户画像、对候选文章做余弦相似度打分、输出 TopN 推荐列表。
  1. profile.update(pool[hid]["tags"])用户每点过一篇,就把该文章的标签累进计数器,相当于老友在“菜的身份卡”上画星。
  2. profile[key] /= total除以标签总数做归一化,得到各项权重相加为 1 的偏好向量,方便和物品向量做余弦比较。
  3. common = set(profile) & set(doc_vec)求用户画像与候选文章标签的交集,只有两个向量都有的维度才参与相似度计算。
  4. norm_u` 与 `norm_d分别计算画像向量和文章向量的模长(平方和开根号),补全余弦公式的分母。
  5. return dot / (norm_u * norm_d + 1e-9)余弦相似度的完整实现,加 1e-9 防止文章向量为零向量时除零报错。
  6. if doc["id"] in history: continue跳过用户已经看过的文章,避免重复推荐,对应真实系统的“已读过滤”。
  7. scored.sort(key=lambda x: x[1], reverse=True)按匹配度降序排列并截断 top_n,完成 TopN 推荐。

常见误区

误区基于内容的推荐既然只看物品属性,那它应该完全不依赖用户数据,也就没有隐私风险了吧?这样理解对吗?

正解误会了。CB 虽然不依赖“其他用户”的数据,但构建用户画像恰恰需要“你本人”的历史行为——点击、停留时长、收藏、付费。这些行为数据本身就是高度敏感的个人信息。CB 只是把“横向看别人”换成了“纵向看自己”,数据脱敏、差分隐私、本地化存储等隐私保护手段一样都不能少。

为何常见:人们容易把“不使用别人的数据”误听成“不使用数据”,忽略了画像本身就是用户数据的浓缩产物。

误区给物品多塞些特征维度,把标签、颜色、字数、作者、文章编号全部堆进向量,CB 效果肯定更好吧?

正解特征并非越多越好。维度爆炸会带来三重副作用:计算开销陡增、稀疏性加剧(很多维度大部分物品为 0)、噪声维度稀释真正的信号。而且像“文章 ID”这种高基数特征还会制造“伪相似”。正确的做法是做特征筛选、降维(如 PCA、NMF)和归一化,让每个维度都确实携带语义。

为何常见:直觉上“信息多等于决策准”,但机器学习的铁律是“垃圾进垃圾出”,冗余特征引入的是噪声而非信息。

误区CB 是靠关键词和标签工作的,抖音、小红书这种图片视频平台根本用不上它吧?

正解能用。图片视频也有“内容特征”:封面图可由预训练视觉模型(如 ResNet、CLIP)抽取向量,音频可抽声纹特征,标题文案和话题标签走文本管线,甚至用户评论也能做二次特征。像抖音的“相关推荐”、小红书的“相似笔记”,底层都有内容特征参与。

为何常见:教材里 CB 常以新闻文本举例,初学者容易把“常用示例”当成“能力边界”。

误区用户画像构建完成之后直接复用不就行了?用户口味又不会天天变。

正解用户兴趣会漂移——今天狂刷考研资料,考上之后系统还狂推考研内容,用户只会觉得“这 App 不懂我”。所以画像必须做时间衰减和增量更新,让近期行为的权重逐渐盖过远期行为。否则画像越老,推荐越脱离现实。

为何常见:“画像”这个词听起来像一个静态档案,让人忽略了兴趣是随时间连续变化的动态过程。

面试题

Q1. 关于基于内容推荐 CB 的核心思想,下列说法正确的是?

单选题 · easy

  • A.靠物品属性匹配用户偏好← 正确答案
  • B.靠其他用户行为做推断
  • C.靠社交关系链做推荐
  • D.靠人工运营编辑来筛选

答案:A。CB 从物品自身属性出发,以用户画像与物品特征的相似度打分,完全不依赖“别人点过什么”,这正是它和 CF 的根本分野。B 说的是协同过滤,C 是社交推荐,D 是运营手段而非算法思想。

Q2. 冷启动场景下 CB 的优势主要体现在哪里?

单选题 · easy

  • A.新文章发布即有内容特征← 正确答案
  • B.新用户无需任何行为数据
  • C.冷启动不需要用户画像
  • D.冷启动完全无需特征工程

答案:A。新文章一发布就能用 TF-IDF 或标签体系提取内容特征,无需等待点击数据,因此能立即参与召回——这是 CB 冷启动的底气。B 错在即便新用户也需要问卷或勾选标签来建画像;C、D 与事实相反。

Q3. TF-IDF 中 IDF 的作用是什么?

单选题 · mid

  • A.衡量词的稀有价值与区分度← 正确答案
  • B.统计关键词出现的总次数
  • C.计算词在整个文本的位置
  • D.统一所有向量的维度数量

答案:A。IDF 等于 log(N / df_t),包含某词的文档数越少,IDF 越大,说明该词越稀有、越能区分主题;“的”“了”这类通用词的 IDF 趋近于 0 被压权。B 描述的是 TF 的职责,C、D 与 IDF 无关。

Q4. 构建用户画像的核心素材是什么?

单选题 · mid

  • A.用户的历史行为数据← 正确答案
  • B.全站的实时热度榜单
  • C.物品的出厂批次号
  • D.系统运行的日志大小

答案:A。用户画像由用户对物品的行为(点击、收藏、付费)对应的特征向量加权累加归一化而来,行为数据是唯一原料。全站热度属于群体信号,是 CF 的素材;批次号、日志大小与用户偏好无关。

Q5. 余弦相似度对下列哪个因素不敏感?

单选题 · mid

  • A.向量的整体长度大小← 正确答案
  • B.两个向量间的角度差
  • C.特征空间的维度分布
  • D.向量各维度的权重值

答案:A。余弦相似度先除以两个向量的模长,把长度伸缩抹平,只保留方向夹角信息。B 中夹角恰恰是它测量的对象;C、D 发生变化必然改变方向,从而影响余弦值。

Q6. 下列哪个是 CB 的典型局限?

单选题 · mid

  • A.推荐结果容易缺乏多样性← 正确答案
  • B.完全无法处理文本内容
  • C.无法向老用户做推荐
  • D.必须依赖大量人工标注

答案:A。CB 只推与历史兴趣相似的内容,时间长了用户看到的世界越来越窄,即信息茧房。它天生擅长文本;老用户画像反而更丰富;特征并不必然依赖人工标注,可用规则与预训练模型兜底。

Q7. 关于混合推荐,下列说法正确的有哪些?

多选题 · hard

  • A.平衡协作与内容两路推荐← 正确答案
  • B.融合可以缓解信息茧房现象← 正确答案
  • C.混合后不再需要单独评估效果
  • D.权重系数应由 A/B 实验确定← 正确答案

答案:ABD。加权融合用一个可调系数 α 同时考虑“内容匹配(CB)”和“群体行为(CF)”,兼顾相关性与多样性,CF 的引入能带来跨类别惊喜从而缓解茧房;α 需要通过 A/B 实验择优。C 说反了,混合之后更要做效果评估。

Q8. 下列哪些属于物品特征提取的手段?

多选题 · mid

  • A.标题关键词与标签体系← 正确答案
  • B.文本经 TF-IDF 转向量← 正确答案
  • C.图片视觉特征映射向量← 正确答案
  • D.全站点击量的实时排序

答案:ABC。标签体系、TF-IDF 文本向量、图像视觉向量都是典型的内容特征提取手段,它们把非结构化内容变成可计算的数值向量。D 是行为统计信号,属于 CF 的输入而非内容特征。

Q9. 关于 CB 在冷启动中的应用,说法正确的有哪些?

多选题 · mid

  • A.新文章靠自身特征即可召回← 正确答案
  • B.新用户可用问卷快速建画像← 正确答案
  • C.冷启动阶段无需计算相似度
  • D.冷启动只能等七天行为积累

答案:AB。CB 冷启动有两条腿:新物品“自带特征”即时召回,新用户“问卷或勾选”快速建画像。但无论哪条腿,最终都要算相似度才能打分排序;也无需等待行为积累,这正是 CB 优于 CF 的关键。

Q10. 用户画像按公式 u^(t+1) = 0.5·u^(t) + 1·v 更新,已知 u^t = (1,2),v = (1,0),更新后的画像为?

单选题 · extreme

  • A.(1.5, 1.0)← 正确答案
  • B.(0.5, 1.0)
  • C.(2.0, 1.5)
  • D.(1.0, 0.5)

答案:A。直接代入时间衰减公式:0.5×(1,2) = (0.5,1),再加上新行为增量 1×(1,0) = (1,0),得到 (1.5, 1.0)。这道题考察对“旧画像衰减 + 新行为融入”这一更新机制的理解。