推荐系统从0到1[一]:数据与画像

年终了,终于可以在需求的夹缝中喘息一会。回望2017年,最大的成就莫过于从0到1搭建起了一套支持多业务场景、高并发访问、高时效性的新闻推荐系统。这其中自是暗坑无数,趁着还未淡忘,将系统搭建过程中遇到的困难与解决方法记录于此。

0. 概况

以我们目前的推荐系统架构为例:

推荐系统是个很复杂的工程,对于算法和工程上的能力都是一个挑战。本文只是尝试从几个大模块简述上手搭建推荐系统的过程,不会深入探讨。然而要想推荐达到可观的效果,深入挖掘每个模块,研读论文、优化架构是必不可少的。以下我会从数据、画像(内容/用户)、召回和排序几个部分分别详述。

1. 数据

推荐系统,最重要的是数据。数据决定了算法的上界,再牛逼的算法也只是逼近这个上界而已。因此搭建系统时,首要考虑完善数据。这里数据包含两类:内容数据与用户数据。

1.1. 内容数据

这个很好理解,内容指的是推荐系统要推荐的item。电商就是商品,电影网站就是电影,我搭建的是新闻推荐系统,所以内容就是新闻。获取手段可以是网站内部发文,也可以是外部抓取,基础爬虫我就不赘述了,另外内容的版权问题也是需要注意的。抓取到之后我们需要对内容落地,这一步的关键是数据格式的规范化。考虑到我们的内容很可能是从不同数据源抓取,有着不同格式,为了方便日后的利用,大致需要遵从如下步骤,对原始数据进行ETL:

  1. 按推荐需求指定落地内容字段
  2. 对内容字段进行标准化处理,如正文提取、一致编码
  3. 选择合适的存储方式,如MySQL、MongoDB、HDFS

需要明确的是,上述系列行为都是为最终的推荐服务的。首先,需要考虑业务侧需要展现哪些属性(如标题、缩略图、摘要);其次,还需要考虑算法侧提取内容特征需要哪些属性(如正文、发布时间)。我在系统搭建的过程中,遇到最头疼的问题就是在NLP时需要依据某个内容属性而源数据没有抓取该属性,因此做抓取前尽量考虑周全,预留好一些字段是很有必要的。

以从腾讯网抓取的新闻部分属性为例:

1.2. 用户数据

搞定内容之后,我们还需要了解用户,推荐的基础也是用户的行为。在新闻网站上,最简单的行为就是点击。一名用户在网站上点击了一条新闻,我们可以认为他对这条新闻感兴趣,此时前端需要将这条记录上报到后台,后台再将log落地。这个过程可以是实时的,也可以用消息队列的方式分批处理,总之,依据场景需求以及系统架构能力。一条最简单的log如下:

user_id,news_id,timestamp  

user_id可以是用户手机的IMEI标识、PC的MAC地址、浏览器的Cookie ID等等,总之是需要能唯一标识用户的序列。当然这里涉及到的一个问题是,一个用户可以在多个终端登录,所以我们还需要用户的登录态来解决一对多的问题,比如用登录QQ、微信账号来做一个关联映射。

上述列举的log只包含最简单的信息,复杂的推荐需要更多的信息,比如来源IP(用以识别用户登录地域),收藏、评论等行为(造成不同兴趣权重),曝光行为(用于之后CTR模型的训练)等等。

有了内容数据和用户数据之后,我们已经可以建立一些简单基于用户行为的推荐策略了,比如itemCF、userCF,具体实现方式我在之前的文章里写过:http://septimusliu.com/2016/06/20/tui-jian-xi-tong-chu-tan ,这里不再赘述。但基于用户行为的策略,往往在系统冷启动时表现不会太好,我们还需要更多维的推荐策略。

2. 内容画像

众所周知,基于行为推荐需要一定的用户行为积累,而新闻生产速度很快,时效性要求又比较高,这时候我们需要一些 Content-based 方法来做推荐。内容画像是实现的基础。

2.1. 文本分类

分类,是新闻语义特征里颗粒度最粗的一个特征。根据分类可以对文本有一个基本的语义划分,可以让用户对兴趣内容有较为明显的感知,所以分类往往是内容画像的第一步。

在分类之前,我们首先要制定统一的分类体系,根据业务需求按颗粒度区分一/二级分类。这一步可以人工标注,也可通过无监督聚类的方法。总之,这对于融合多来源、多类型的内容数据至关重要。

分类的方法有很多,传统统计方法里如 Naive Bayesian、SVM,深度学习里的 CNN、LSTM 等都可以胜任。不过在大多数情况下,传统方法已经可以做到很好的效果,且实现简单,因此我们通常选择前者。

2.2. 关键词提取

分类完成之后,可以说我们的内容画像已经初见端倪。然而,仅仅精确到分类颗粒度的个性化推荐是很难满足用户的。用户对于文章的兴趣,往往精确到某个明星、某支球队,要捕捉到这种颗粒度的信息,只要依赖于关键词。

关键词提取是对于文章中出现的具有代表语义作用的词汇进行提取,并赋予权重。这类算法很多,baseline 的方法比如 tfidf、textrank,都能做到很好的效果。当然,如果我们要做到更精确,还需要结合业务数据做一些人工规则,比如将词性、实体、词出现位置等特征与 baseline 方法进行结合,或者用人工标注的方法转换为有监督学习的问题。

2.3. 主题抽取

分类和关键词,颗粒度的跨度其实是比较大的。在基于语义的个性化推荐过程中,一些冷门关键词往往比较难以命中,为了弥补这个真空,文本主题的概念就派上用场了。

图2-1 LDA示意图(来源:由Slxu.public - 自己的作品,CC BY-SA 3.0,https://commons.wikimedia.org/w/index.php?curid=7922733)

诸如 pLSA、LDA 的主题模型假设一篇文档的生成过程是这样的:

  1. 作者从文档 - 主题分布 θ 中随机挑选一个主题 zi
  2. 作者从主题 - 词分布 φ 中随机挑选一个词 wj
  3. 重复步骤1,直到文档所有词生成完成

LDA 与 pLSA 不同之处在于 LDA 还假设这两个分布也不是固定的,而是遵循两个狄利克雷先验分布。总之,这类算法最终计算出的是文档集合中存在的“隐分类”,表征文档语义中存在的一些潜在关联。主题的维度我们一般设置为较大的数字,这样我们便拥有了一个颗粒度介于分类与关键词之间的特征。LDA 的实现方法可以参照之前的文章:http://septimusliu.com/2017/06/24/zai-sparkshang-yong-ldaji-suan-wen-ben-zhu-ti-mo-xing

有了上述三类特征后,内容画像已经可以满足大部分需求了。须知,上文所说的方法都是比较基础的方式,像 CNN、RNN、Attention Model 都是可以尝试的方法,NLP 的研究和优化需要投入大量的精力,如果想在这上面深挖,建议系统学习 NLP 相关课程。

3. 用户画像

3.1. 兴趣画像

有了内容画像,我们再来计算用户的兴趣画像就是水到渠成的事情了。简单的方法就是根据用户的行为,检索到一定时间内用户所有有过正向行为(点击/收藏/评论)的 news,把它们看成一篇内容,对所有特征进行线性加和,作为用户在该时间窗内的兴趣画像。用户 u 的当天兴趣画像计算公式如下:

其中 m 为用户 u 在当天产生正向行为的文档集合,n 为文档 i 的特征集合。θj 表示文档 i 第 j 个特征的权重,P(θj) 表示第 j 个特征的先验概率(这一步主要是为了减弱头部文章对用户画像的影响,若某天某一类特征的新闻很热,那么有可能大多数用户画像里都会有这类特征,但它并不能真正代表用户的兴趣倾向)。

随着时间推移,用户的兴趣会发生迁移,因此我们需要加上时间的影响因素:

yt 表示 t 时刻的用户画像,yt-1 表示上一时刻的画像,λ 为时间衰减因子。

3.2. 基础画像

除了上述的用户兴趣画像外,还有一些用户的属性是我们感兴趣的,比如用户的性别、年龄、职业、所处地域,这部分可以根据业务特点来获取,这些我们称之为基础画像。基础画像虽然没有兴趣画像颗粒度细致,但在冷启动、地域强相关等业务场景也是比较重要的。

在业务实践中,我们发现用户的兴趣变化是很快的,并且很难用某一种状态涵盖住用户所有的兴趣范围。比如当我们在浏览新闻时,我们的近期浏览记录也许的确反映了我的兴趣变化,但也有可能我只是对热点感兴趣,抑或是想试探一下不同领域的阅读,再或者仅仅是手抖点错了。再比如,系统依据用户所处地域推荐内容,然而这个用户有可能只是来外地出差,他更感兴趣的可能依旧是常住地的新闻……无论如何,在计算画像的时候我们无法确保用户的意图,因此在快速反馈用户行为的同时,加上多状态的用户画像是有必要的。通常我们的做法是分别记录用户的长期和短期画像,在针对不同的画像做不同的推荐召回,以此满足用户不同状态下的阅读需求。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏高性能服务器开发

去BAT,你应该要看一看的面试经验总结

首先是简单地了解下你之前的工作经历和项目经验,然后就是算法和数据结构题目,具体涉及到以下内容:

23620
来自专栏JavaQ

如何用六点教会老婆写 Python ?

code就就是一种语言,一种计算机能读懂的语言。计算机是一个傻逼,他理解不了默认两可的任何东西。比如,你让你老公去买个西瓜,你老公会自己决定去哪里买,买几个,找...

12120
来自专栏灯塔大数据

技术 | Python从零开始系列连载(二十一)

为了解答大家初学Python时遇到各种常见问题,小灯塔特地整理了一系列从零开始的入门到熟练的系列连载,每周五准时推出,欢迎大家学积极学习转载~

15120
来自专栏高性能服务器开发

算法与数据结构系列之探秘堆结构

此处所说的堆为数据结构中的堆,而非内存分区中的堆。堆通常可以被看做是树结构,满足两个性质: 1)堆中任意节点的值总是不大于(不小于)其子节点的值; 2)堆是一棵...

17220
来自专栏灯塔大数据

原创译文 | 微软放大招!面部识别无歧视,Face API更加精准识别人类肤色

微软近日在博客文章中宣布了Face API的重大更新,它改进了面部识别平台识别不同人种性别的能力,此前,这一直是计算机视觉平台面临的挑战。

11640
来自专栏iOSDevLog

决策树与博弈树

你还记得史努比这只可爱的小狗吗?它的主人是查理 · 布朗(Charlie Brown),那个头上只有几根毛的可爱的男孩子。其实他俩是漫画《花生》(Peanut)...

23820
来自专栏高性能服务器开发

『腾讯后台开发』实习生技能要求

19320
来自专栏JavaQ

HashMap死循环精简说

在JDK1.8之前的版本中,HashMap的底层实现是数组+链表。当调用HashMap的put方法添加元素时,如果新元素的hash值或key在原Map中不存在,...

12430
来自专栏开源优测

RFC2861 TCP 拥塞窗口检验

15610
来自专栏灯塔大数据

干货 | 高级Java面试通关知识点整理!

14320

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励