第3章:基于内容的推荐——用户画像构建、物品特征提取、相似度计算

好,咱们进入第三讲。前面两章我们聊了冷启动的宏观思路和协同过滤的局限性。这一章,我带你深入一个非常实在的技术方向——基于内容的推荐

说白了,就是让系统“看懂”用户和物品。用户喜欢什么?物品有什么特点?然后算一算它们有多匹配。这招在冷启动场景下特别管用,因为不需要用户历史行为数据。

3.1 用户画像构建:给用户贴标签

用户画像,听起来高大上,其实就是把用户抽象成一组特征向量。我习惯把它拆成三步走:

  1. 显式特征:用户注册时填的性别、年龄、职业、地域。这些最直接,但往往不够用。
  2. 隐式特征:用户浏览了什么、点击了什么、收藏了什么。注意,冷启动阶段这部分数据很少,所以我们要靠其他手段。
  3. 推理特征:根据用户少量行为,用规则或模型推断出偏好。比如用户看了3篇“机器学习”文章,我就可以推断他对“AI”感兴趣。

核心要点:冷启动阶段,用户画像的构建要“粗粒度”一些。别想着一步到位,先给用户打上大类标签,比如“科技爱好者”、“美妆达人”。等数据多了再细化。

我在项目中遇到过一个问题:用户画像太细,导致推荐结果过于局限。比如一个用户看了《三体》,系统就疯狂推科幻小说,结果用户其实也喜欢历史。嗯,这里要注意——画像要有层次,大类和小类并存。

3.1.1 画像存储结构

我建议用标签权重的方式存储。每个标签带一个权重值,表示用户对该标签的偏好程度。

{
  "user_id": "u12345",
  "profile": {
    "年龄": 28,
    "性别": "男",
    "兴趣标签": {
      "科技": 0.85,
      "历史": 0.60,
      "美食": 0.40,
      "运动": 0.20
    },
    "活跃时段": "21:00-23:00",
    "设备": "iPhone 14"
  }
}

你看,这个结构很清晰。权重值可以通过用户行为来更新。比如用户点击了一篇“历史”文章,权重就加0.05;如果长时间不点击,权重就衰减。

避坑指南:我曾经把用户画像做得太复杂,用了上百个标签。结果计算相似度时性能惨不忍睹。后来我学乖了——标签数量控制在20-50个,效果和性能都能兼顾。

3.2 物品特征提取:让机器理解物品

物品特征提取,是内容推荐的另一条腿。物品可以是文章、商品、视频、音乐……不同物品,提取方式不同。

我个人习惯把物品特征分为三类:

特征类型 举例 提取方法
结构化特征 价格、品牌、分类、颜色 直接从数据库字段获取
文本特征 标题、描述、评论 TF-IDF、Word2Vec、BERT
多媒体特征 图片、音频、视频 CNN、ResNet、CLIP

对于文本类物品,我最常用的是TF-IDF。为什么?因为它简单、高效、可解释性强。你想想看,一个词在文档中出现的次数越多,在其他文档中出现的越少,那这个词就越能代表这篇文档。

3.2.1 文本特征提取实战

假设我们有一篇新闻文章,标题是“苹果发布新款iPhone,搭载A18芯片”。

from sklearn.feature_extraction.text import TfidfVectorizer

# 假设我们有3篇文档
docs = [
    "苹果发布新款iPhone,搭载A18芯片",
    "华为推出Mate 60,搭载麒麟芯片",
    "小米发布Redmi Note,主打性价比"
]

vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(docs)

# 查看特征词
print(vectorizer.get_feature_names_out())
# 输出:['A18' 'iPhone' '华为' '发布' '苹果' ...]

# 查看第一篇文章的特征向量
print(tfidf_matrix[0].toarray())

你看,代码很简单。但实际项目中,我会做分词去停用词词干提取等预处理。中文的话,我推荐用jieba分词。

注意:TF-IDF有个缺点——它无法捕捉语义相似性。比如“苹果”和“iPhone”在TF-IDF中是两个完全独立的词。如果你需要语义理解,可以考虑用Word2Vec或BERT。

3.3 相似度计算:找到最匹配的

有了用户画像和物品特征,接下来就是算相似度了。这一步决定了推荐的质量。

我常用的相似度计算方法有四种:

  1. 余弦相似度:最常用,适合高维稀疏向量。取值范围[-1, 1]。
  2. 皮尔逊相关系数:对用户评分偏差不敏感,适合评分数据。
  3. 欧氏距离:直观,但受量纲影响大,需要归一化。
  4. 杰卡德相似系数:适合集合数据,比如用户喜欢的标签集合。

3.3.1 余弦相似度实战

我个人最常用余弦相似度。为什么?因为它关注方向而非长度。比如两个用户,一个打分全是5分,一个全是4分,但偏好方向一致,余弦相似度会很高。

import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# 用户画像向量(假设3个特征:科技、历史、美食)
user_vector = np.array([[0.8, 0.6, 0.4]])

# 物品特征向量
item_vectors = np.array([
    [0.9, 0.1, 0.2],  # 科技类文章
    [0.2, 0.8, 0.3],  # 历史类文章
    [0.1, 0.2, 0.9]   # 美食类文章
])

# 计算相似度
similarities = cosine_similarity(user_vector, item_vectors)
print(similarities)
# 输出:[[0.82, 0.55, 0.38]]

你看,用户对科技类文章的相似度最高(0.82),其次是历史(0.55),最后是美食(0.38)。这个结果很符合直觉。

关键点:相似度计算前,一定要做特征归一化。否则数值大的特征会主导结果。我习惯用Min-Max归一化或Z-score标准化。

3.4 冷启动场景下的特殊处理

在冷启动场景下,基于内容的推荐有几个坑要避开:

  • 新用户没有画像:怎么办?我建议用默认画像。比如新用户注册时,根据他选的兴趣标签,生成一个初始画像。或者用热门物品的特征作为默认画像。
  • 新物品没有特征:这个好办。物品特征可以从标题、描述、分类中提取。实在不行,用人工标注。我早期做电商推荐时,就是让运营团队给新品打标签。
  • 特征稀疏问题:有些物品只有很少的特征词。这时候可以用特征扩展,比如基于知识图谱,把“iPhone”扩展到“苹果”、“智能手机”、“A18芯片”等。

我的经验:我曾经做过一个新闻推荐系统,冷启动阶段用户画像只有3-5个标签。我用了标签传播算法,把用户点击过的文章标签传播到相似标签上。效果提升很明显,推荐覆盖率提高了30%。

3.5 小结与思考

这一章我们聊了基于内容推荐的三个核心环节:

  • 用户画像构建:从显式、隐式、推理三个维度给用户打标签
  • 物品特征提取:结构化、文本、多媒体三种特征提取方法
  • 相似度计算:余弦相似度、皮尔逊、欧氏距离、杰卡德

基于内容的推荐,说白了就是“物以类聚,人以群分”。它不依赖用户行为,特别适合冷启动。但它的缺点是推荐结果不够多样化,容易陷入“信息茧房”。

下一章,我会讲如何把基于内容的推荐和协同过滤结合起来,取长补短。嗯,那就是混合推荐了,敬请期待。