zoukankan      html  css  js  c++  java
  • 数据中台实战(十):如何从0到1搭建推荐平台?

    上一篇数据中台的实战文章讲了《数据中台实战(九):如何搭建全渠道自动化的平台》,这次我们基于实战看一下如何从0到1搭建推荐平台。

    一、什么是推荐系统

    推荐系统的核心是要解决人货匹配的问题。

    我们拿电商平台举例,作为一个电商平台,就是为了卖货,怎么把我们的货卖出去并且用户还比较满意呢?一定是找到有需求的用户。

    当我们平台有10个用户,50件单品在卖的时候,如果平台有一个运营就能搞定所有的事情,运营甚至可以挨个问平台的10个用户,他们到底想要那些货,然后在这50件单品中找到用户想要的货人工推荐给平台的用户。

    当用户发展到一定的规模,比如1万,5000件单品,运营的做法是给用户打上各种各样的标签,通过标签形成用户画像,再基于用户画像做用户分群,每个群是一类人,那么高价值的用户群,一定是特殊对待,倾斜更多的资源,只有针对这些高价值用户才有精力提供一对一的服务,这样效率才会最高。

    可以想一下如果当平台的用户已经突破一个亿人这么一个规模,单品突破10万的规模,我们该怎么解决人货匹配的问题呢?

    随着用户量的增长有一点是不变的,那就是用户喜欢什么样的商品,我们如果了解了用户需要什么货,也就能把我们的10万商品卖出去。

    推荐就是用数学的方法计算并猜测用户到底需要什么商品,通过数据可以计算出用户到底会喜欢那些商品,只是一个概率,当把这个概率提高到了一定的水平,那么就可以把这些商品展现给我们的用户,说不定他就买了我们推荐的商品。

    接下来核心问题就比较明显了:我们应该怎么计算用户到底喜欢那些商品呢?

    答案就是用户的数据。

    用户的数据其实分为隐性数据和显性数据。

    隐性数据是什么?我们的埋点就派上了用场,用户的每次浏览,点击都会记录这个用户是谁,什么时候,在什么地点,用什么设备,来看我们的那个商品,看了多久。

    这些数据对判断用户是否对该件商品感兴趣是有价值的,为什么?

    比如对于同一个商品来说,一个用户连续3天都在看,而且停留很久,另外一个用户到我们网站后压根就没看这个商品,那么相对于第一个用户来讲,我们就可以直接判定这个用户是对这个商品更感兴趣的。

    第二部分是用户的显性数据,比如用户下单的数据,加购的数据,收藏的数据等业务数据,还有用户填的一些资料,比如用户的性别,地区等数据,对一个用户越了解,就可以更加精确的判断出他会买那些商品。

    现在的电商产品推荐基本是标配的,比如你在啊猫,啊狗网站上看了一个最新款的苹果手机,那么在电商网站的某个猜你喜欢模块一定能看到这个手机是排在了最上面,如下图1-1所示。

    图1-1 淘宝推荐猜你喜欢模块

    比如你买过了这个手机,那么可能这个猜你喜欢会给你推荐苹果手机类似的商品,比如给你推荐一个 iPad,如下图1-2所示:

    这时你可能就会有比较大的几率下单。

    图1-2淘宝推荐看了又看模块

    二、推荐系统架构

    2.1 推荐系统功能架构

    如下图1-3所示是一个典型的推荐系统功能架构图,一个推荐系统主要分为三块,分别为召回、过滤、排序。

    图1-3推荐系统功能架构图

    第一步是召回

    召回就是上图中的N个推荐引擎。

    召回就是通过一定的方式找到用户可能感兴趣的商品。

    召回的方式有3种:

    1. 用户喜欢的物品相似的物品
    2. 和用户有相似兴趣的用户喜欢的物品
    3. 基于用户的标签(用户年龄、性别等)推荐物品

    这三种方式都可以召回一定数量的商品,形成用户感兴趣的商品的候选集。

    最好是能做到每种召回方式都相互独立,这样当其中的一种召回方式效果不好时可以快速的切换。

    特别是在前期,可以每种召回算法单独的运行,通过A/B Test找出最好的推荐引擎。

    第二步是过滤

    把候选集内的商品经过一定的规则,过滤掉有问题的商品。

    比如用户曾经买过的商品、某些质量很差的商品等。

    第三步是排序

    每种召回算法都会给出一个推荐结果,格式基本上都是某人喜欢某个商品概率是多少。

    这里就会产生一个问题,比如召回算法A推荐出商品a,喜欢的概率是0.9,召回算法B推荐出结果b,喜欢的概率也是0.9。

    那么我们应该将a、b那个商品推荐给用户?因为商品a、商品b是在不同的标准推荐出来的,所以没有可比性,就好比每个省的都有一个高考状元,这两个省的高考状元那个更厉害一点呢?因为用的是不同的试卷,所以没办法评估那个更厉害。

    所以就需要排序层再进行一个统一的入学考试,那个状元考的分数高,就说明那个状元更加厉害。

    排序层就是为了解决这个问题,把候选集中所有的商品经过排序算法统一进行一次用户感兴趣程度的排序。

    最后有了候选结果集,由后端工程师通过接口的方式推送给产品线,由产品线负责推荐结果的显示。

    2.2 推荐系统技术架构

    如图2-4是一个典型的推荐系统技术架构,包含了实时推荐、非实时推荐的技术实现。

    图2-4推荐系统技术架构

    第一步是产品线的用户产生的数据包括用户行为数据、用户产生的业务数据,这些数据都可以作为实时推荐、离线推荐的数据源。

    行为数据通过消息队列传输到日志文件或者直接供实时推荐引擎使用。

    业务数据存储在业务数据库,由数据中台同步到数据中台的数据仓库。

    第二步是执行实时层、离线层的计算任务。

    实时层采用流式计算框架如Flink等获取用户近一段时间或者近几次行为可能偏好的商品,再通过偏好的商品,从商品库中计算用户可能感兴趣的商品形成候选结果集。

    离线计算任务一般执行一些离线算法,如基于用户的协同过滤,基于商品的协同过滤,排序算法等,离线任务偏重基于用户的长期兴趣找到用户刚兴趣的商品。

    第三步是实时推荐结果和离线推荐结果的整合。

    实时推荐的结果一般存储在内存数据库中如Redis,离线任务计算好的结果一般存储在MYSQL。

    实时的推荐结果和离线的推荐结果通过一定的规则整合起来形成用户最终的推荐结果。

    第五步是推荐结果的展示。

    当前端发起请求查询用户的推荐结果时,比如点击了猜你喜欢模块,产品线通过接口的方式请求推荐系统,由推荐系统返回第四步整合后的推荐结果。

    三、推荐系统实施流程

    推荐系统在是一个比较大的项目,刚开始接触时可能会觉得无从下手。

    推荐系统属于AI系统,需要大量的算法支撑。

    AI 系统需要灵活地支持各类 AI 任务,解决各类任务敏捷化过程中的需求与痛点。

    当前,企业智能化需求各不相同,导致相应的 AI 任务也种类繁多。

    我们按照面向业务和非面向业务可以把AI系统的任务分为两种,如下图2-5所示:

    图2-5 AI系统任务划分

    第一种是针对某个业务领域内特定类型数据,提供对此类数据的基础 AI 学习、预测、分析能力的计算任务,例如计算机视觉、自然语言处理任务等。

    这种任务很多时候其本身并不直接解决业务需求,常作为基础模型对数据进行初步加工,再由一些面向业务的任务来对接需求。

    这也给算法实施团队充足的时间对横向任务模型进行充分的雕琢,对其敏捷性进行完善。

    这部分属于AI系统底层通用能力,不过多展开。

    第二种则是面向业务具体需求的、如电商领域的推荐系统以及比较常见的用户画像构建、智能问答等。

    实施AI项目的整个流程如下图2-6所示:

    图2-6 AI项目实施流程

    第一步也是需求的定义比如我们推荐系统要解决人货匹配的问题;接下来需要准备数据、处理数据,这里时数据中台的数据开发工程师承担;接下来的特征工程、模型建立及模型的效果评估等算法相关的模块需要算法工程师、标注工程师等角色共同参与完成的。

    也就是说数据中台的团队只需多增加算法团队,就可以完成AI项目的实施。

    那么数据中台和AI系统的关系就比较清晰了,补充了算法团队,推荐系统可以当做数据中台的一部分。

    四、几种经典的推荐算法

    4.1 用户协同过滤算法

    生活中对于我们个人来说是怎么找到我们喜欢的商品呢?比如你要买一个衬衫,你可能会看一下或者问一下周围的朋友都穿的什么,在朋友的影响下,如果近期你真的想买衣服,那么有很大概率会偷偷去网上看一下或者去线下的实体店看一下这件衣服。

    在推荐系统中,这也是一种给用户推荐感兴趣商品的方法,叫基于用户的协同过滤。

    比如在电商产品中,推荐系统的做法也是同样的思路,找到和用户相似度比较的高用户,然后基于和他相似用户喜欢的商品推荐给用户他有可能喜欢的商品。

    在互联网产品中,我们怎么定义那些商品是用户喜欢的商品呢?可以通过用户的行为打分的方式,比如用户浏览了某个商品我们打1分,用户收藏了某个商品我们给3分,用户加购了某个商品我们给5分,用户下单了某个商品我们给7分,这样给所有产生过用户行为的商品都打分,最高分可以定义为用户最喜欢的商品,最低分相对来说用户大概率没那么喜欢。

    基于上面的思路,我们可以看出基于用户的协同过滤主要分为2个步骤:

    1. 找到和目标用户兴趣相似的用户集合
    2. 找到这个集合中用户最喜欢的,且目标用户没有听说过的物品推荐给目标用户

    我们先看第一步怎么算,通常用Jaccard公式或者余弦相似度计算两个用户之间的相似度。

    设N(u)为用户u喜欢的物品集合,N(v)为用户v喜欢的物品集合,那么u和v的相似度怎么计算呢?

    Jaccard 公式:

    余弦相似度:

    假设目前共有4个用户:A、B、C、D;共有5个物品:a、b、c、d、e。

    用户与物品的关系(用户喜欢物品)如下图2-7所示:

    图2-7用户与物品的关系

    如何一下子计算所有用户之间的相似度呢?为计算方便,通常首先需要建立“物品—用户”的倒排表,比如物品a被A、B两个用户喜欢,物品b被A、C两个用户喜欢等。

    具体如下图2-8所示:

    图2-8用户与物品的关系

    然后对于每个物品,喜欢他的用户,两两之间相同物品加1。

    例如喜欢物品 a 的用户有A和B,那么在矩阵中他们两两加1。

    如下图2-9所示:

    图2-9加1操作计算后的矩阵

    计算用户两两之间的相似度,上面的矩阵仅仅代表的是公式的分子部分。

    以余弦相似度为例,对上图2-10所示进行进一步计算:

    图2-10经过余弦相似度计算后的矩阵

    到此,计算用户相似度就完成了,可以很直观的找到与目标用户兴趣较相似的用户。

    接下来我们看一下第二步,首先需要从矩阵中找出与目标用户u最相似的K个用户,用集合S(u,K)表示,将S中用户喜欢的物品全部提取出来,并去除u已经喜欢的物品。

    对于每个候选物品i,用户u对它感兴趣的程度用如下公式计算:

    其中rvi表示用户v对i的喜欢程度,在本例中都是为1,在一些需要用户给予评分的推荐系统中,则要代入用户评分。

    举个例子,假设我们要给A推荐物品,选取K=3个相似用户,相似用户则是:B、C、D,那么他们喜欢过并且A没有喜欢过的物品有:c、e,那么分别计算p(A,c)和p(A,e):

    从计算结果来看用户A对c和e的喜欢程度可能是一样的,在真实的推荐系统中,只要按得分排序,取前几个物品就可以了。

    基于物品的协同过滤算法有这么几个问题:

    1. 用户数量往往比较大,计算起来非常吃力,成为瓶颈;
    2. 用户的口味其实变化还是很快的,不是静态的,所以兴趣迁移问题很难反应出来;
    3. 数据稀疏,用户和用户之间有共同的消费行为实际上是比较少的,而且一般都是一些热门物品,对发现用户兴趣帮助也不大。

    4.2 基于物品的协同过滤算法

    如下图2-11所示,假设有三个用户和四个物品,分别是橘子、草莓、苹果和香蕉。

    我知道第三个用户他购买苹果,接下来,我问你:在其他的三个他没有购买的物品,橘子,草莓和香蕉里面,第三个用户可能会最喜欢的哪个?

    图2-11基于物品协同过滤算法案例

    我们希望给第三个用户推荐的物品应该是跟他已经购买的苹果相似的物品,那什么物品可以和苹果相似呢?

    我们可以这样思考,什么物品在用户购买苹果之后,被同时购买的次数是最多的?

    我们先看香蕉,香蕉有没有跟苹果同时购买?

    有,第一个用户,他同时购买了橘子、苹果和香蕉,香蕉我们算它得了一分,因为跟苹果同时购买了,所以加一分;

    那我们再看草莓,草莓没有任何人买草莓的同时也买过苹果,草莓得分是0分;

    那么再看橘子,第一个用户,他同时购买了苹果和橘子,第二人也同时购买了苹果和橘子,所以说橘子得两分,它跟苹果的相似度是2。

    这样我们就发现苹果跟橘子相似度是2,苹果和草莓相似度是0,苹果跟香蕉相似度是1,得出结论:橘子跟苹果最相似,我们就给第三个用户推荐橘子,这就是协同过滤的精髓。

    这种方法在推荐系统中叫基于物品的协同过滤。

    实现的步骤分为三步:

    1. 找到目标用户曾经喜欢的商品
    2. 计算物品的相似度
    3. 将相似度最高的商品推荐给用户

    接下来我们通过一个简单的例子,来说明一下这个流程应该怎么实现:

    第一步是计算物品之间的相似度。

    我们要如何确定物品之间的相似度呢,根据物品历史被喜欢的情况,假如某两个物品历史共同被许多用户喜欢,则说明这两个物品是相似的。

    假设喜欢物品a的用户数为N(a),喜欢物品b的用户数为N(b),那么a与b的相似度为:

    上述公式可以理解为喜欢A物品的用户中,有多少比例的用户也喜欢B,比例越高,说明A与B的相似度越高。

    但是这样的公式有一个问题,如果物品B很热门,很多人都喜欢,那么相似度就会无限接近1,这样就会造成所有的物品拿出来,都与B有极高的相似度,这样就没有办法证明物品之间的相似度是可靠的了。

    为了避免出现类似的情况,可以通过以下公式进行改进:

    第二步是根据物品的相似度和用户的历史行为给用户推荐。

    获得了物品的相似度后,则根据以下公式来计算用户u对物品b的兴趣:

    其中,N(u)是用户喜欢物品的集合,S(b,K)是和物品b最相似的K个物品的集合,Wab是物品a和b的相似度,Rua是用户u对物品a的兴趣。

    我们假设:

    • 用户A喜欢:abc,
    • 用户B喜欢:bcd,
    • 用户C喜欢:cd。

    那么喜欢一个物品的用户数为:

    • 喜欢a的用户数:1
    • 喜欢b的用户数:2
    • 喜欢c的用户数:3
    • 喜欢d的用户数:2

    那么同时喜欢两个物品的用户数为:

    • 喜欢ab的用户数:1
    • 喜欢ac的用户数:1
    • 喜欢bc的用户数:2
    • 喜欢dc的用户数:2

    物品相似度为:

    ab相似度为:

    ac相似度为:

    bc相似度为:

    cd相似度为:

    如果某个用户对a的兴趣度为1,对b的兴趣度为2,那么预测他对c,d的兴趣度为:

    c:1×0.58+2×0.82=2.22

    d:0

    和基于用户的协同过滤不同,基于物品的协同过滤首先计算相似物品,然后再根据用户消费过、或者正在消费的物品为其推荐相似的,基于物品的算法怎么就解决了基于用户协同过滤暴露的那些问题呢?

    • 首先,物品的数量,或者严格的说,可以推荐的物品数量往往少于用户数量;所以一般计算物品之间的相似度就不会成为瓶颈。
    • 其次,物品之间的相似度比较静态,它们变化的速度没有用户的口味变化快;所以完全解耦了用户兴趣迁移这个问题。
    • 最后,物品对应的消费者数量较大,对于计算物品之间的相似度稀疏度是好过计算用户之间相似度的

    五、推荐系统的评测指标

    如何评判一个推荐系统的好坏呢?一般来说分为三种方式:

    我们先看下推荐系统的数据指标有哪些:

    数据指标又分为两种,一种是商业指标,看推荐系统的最终交易额相关指标。

    我们做推荐系统的目的是为了代替人工给用户推荐商品,提高效率,实现用户的千人前面,带来更多的交易额。

    商业指标有以下几个:曝光次数、商品的PV、商品的UV、商品支付人数、支付金额、支付件数。还有就是点击率、支付转化率,点击率=商品PV/曝光次数,支付转化率=商品支付人数/商品UV。

    接下来我们看看这些指标该怎么计算:

    5.1 曝光次数

    统计推荐模块曝光量的方式有2种:

    • 一种是通过数据埋点,当用户在推荐模块拉取商品时由前端工程师异步上传数据到埋点日志服务器,再通过解析埋点日志的方式统计曝光次数。
    • 有一种是通过后端埋点的方式,当用户调用拉取推荐商品的接口时由后端工程师记录当时的推荐场景、算法、用户,商品ID的集合这些关键信息,保存到日志文件,再通过解析日志文件的方式统计曝光次数。

    由于前端埋点有5%的丢失率,计算的指标包括交易额,需要比较准确的数据。

    采用后端埋点的方式统计曝光量会更加准确一些。

    推荐位商品的PV/UV可以通过对推荐位进行常规埋点埋点,由前端工程师开发,当用户每点击一次推荐位的商品,就会通过埋点的方式记录当前的推荐场景,算法ID、商品ID等主要信息。

    涉及到交易额的指标包括支付人数、支付金额、支付件数,也需要通过后端埋点的方式采集,在前文已经讲过,因为电商产品的交易流程有一个断层,用户一般都是先加购再下单,这个断层就会增加前端埋点和数据解析的难度。

    简单的做法是在订单中增加下单来源字段,记录商品的推荐场景,算法ID等信息到购物车,一般来说购物中的数据是存在内存数据库redis里面,用户下单时再从redis中取出放入订单中,这样就保证了数据能够整个链条的记录下来,功能如下图2-12所示。

    图2-12推荐系统监测指标

    还有一种指标是来优化推荐算法的,包括准确率、召回率、覆盖率也是评价推荐系统算法很好的指标,我们先看一下这三个指标是怎么定义的。

    举个例子,比如给用户推荐了100个商品,其中10个用户做了点击,那么准确率就是10%。

    计算准确率要对推荐的商品列表页做埋点,用户每点击一次推荐页商品就会上传商品的ID、用户ID,这样才能记录用户到底点击过那些商品。

    5.2 召回率

    召回率怎么定义呢?

    还是这个例子比如给用户推荐了100个商品,其中10个用户做了点击,用户在我们电商网站一共查看了50个商品,那么推荐系统召回率就是20%。

    5.3 覆盖率

    比如我们电商网站一共1万个SKU,给所有的用户推荐出来SKU为8000,那么这个推荐系统的覆盖率就是80%,覆盖率为100%的推荐系统可以将每个物品都推荐给至少一个用户。

    覆盖率是供应商会比较关注的指标,供应商关系他们的商品有没有推荐给用户。

    当推荐系统搭建好之后可以先组织公司内部人员做测试,比如笔者公司电商产品定位是女装批发平台,主要客户是女性,推荐系统上线前,我们就招募了公司一部分女员工做了测试。

    这些女员工平时在我们的电商平台也会购买一些女装,已经积累了一些数据。

    做灰度测试时,我们的推荐系统最好是能做成准实时,让用户有了新的行为如点击、加购等,再次刷新就能出现新的他们感兴趣的商品,这样也便于我们及时收到反馈。

    我们可以手工统计一下数据比如单个用户的准确率和召回率。

    可以先不要告诉他们这次活动的目的,给他们5分钟让他们逛平台,唯一让他们做的就是记录每次查看的商品名称和位置,这样可以方便我们计算出召回率。

    接下来可以让他们关注下推荐模块,让他们记录推荐了多少个商品,点击了其中的多少个商品,这样可以直接算出来准确率。

    最后再问几个核心问题,如果我们的推荐系统满分是10分,他们给几分,为什么打这样的分数,有无其他的一些建议给我们。

    注意观察他们的情绪及眼神。

    当我们经过内部这一轮内部测试会发现一些问题,可以针对问题进行针对性的修改,当优化出一个稳定的版本后,可以和运营合作邀请几个真实的用户用户来试一下,测试用户的分布要大致保证和真实用户相同如年龄,活跃度等相关智能表的分布。

    可以设计一套方案,让他们参与进来,体验我们的推荐模块,这时可以通过后台收集埋点数据的方式计算这批用户的准确率和召回率。

    六、推荐系统的冷启动

    从上文来看,推荐系统依赖用户的历史行为数据,像某猫、某狗这块大型电商网站,有大量的用户历史行为数据可以利用。

    但是对于一般的推荐系统,特别是刚起步阶段,一般是没有用户行为数据的,这个时候该该怎么办,这也是推荐系统一个比较核心的问题叫“冷启动”问题。

    冷启动主要分为以下几种:

    • 用户的冷启动:这个主要解决给新用户如何推荐商品的问题。当新用户刚进系统是没有历史行为数据的,我们无法通过推荐系统给用户做个性化推荐。
    • 物品冷启动:这个主要解决一个新的物品怎么推荐给他可能感兴趣的用户。
    • 系统的冷启动:一个新开发的产品,只有少量的商品,还没有用户。让用户上线时就可以体验到个性化推荐服务这个问题。

    如何解决这些问题呢,在这里提供一些方案供参考:

    6.1 利用用户注册信息

    用户注册都要填一些信息,比如性别、年龄、第三方登录等信息。

    比如我们可以对用户的注册信息做一个分类,针对不同的性别,和不同的年龄段推荐不同的商品。

    我们还可以通过用户的第三方登录信息,在用户授权的情况下通过社交网络数据拿到用户好友喜欢的一些商品,再推荐给用户,因为都是用户熟悉的朋友,那么他们朋友喜欢的商品,大概率他们也会喜欢。

    6.2 让用户主动选择自己喜欢的商品

    主要方式就是可以让用户选择喜欢的商品或者品类,基于用户选择的结果进行推荐。

    如下图2-13所示,可以让新用户登录后选择自己偏爱的品类,当用户选择后,他的商品列表就会基于他选择的结果进行推荐。

    也可以基于热销的商品推荐给用户,让用户选择,再基于用户的选择推荐合适的商品。

    图2-13让用户选择偏好品类

    6.3 利用物品的内容信息

    物品的冷启动也是一个需要解决的问题,电商网站每天会更新大量的商品,如果新的商品得不到推荐,那么会影响到用户的体验,也得不到业务部门的支持。

    电商网站一般用基于商品的协同过滤,协同过滤的核心是认为物品A和物品B有很大的相似度的原因是因为喜欢物品A的用户大多数也喜欢物品B,可以看得出物品的协同过滤是很依赖用户的行为数据的,因为用户的行为数据决定用户是否会喜欢这件商品。

    但是对于新物品是没有用户行为数据的,就很难推荐到新物品,就算是有用户对商品产生了行为,那么商品之间的相似度也是需要大量的计算,无法做到及时反馈给用户。

    那么怎么解决这个问题呢?

    我们可以利用物品的内容信息,比如对于一个衣服来讲衣服的名字,品类,品牌,价格段都是物品的内容信息。

    如果做了商品的价格段标签那么可以精准推荐到同品牌、同品类下同价格段的商品那个适合用户,比如同品牌、同款、同价格段的毛衣。

    商品的名字也有多的内容信息。

    我们可以针对商品名称,建立分词库,基于分词给商品打上标签,可以基于标签给用户推荐类似标签的商品。

    七、从0到1打造一个离线推荐系统

    7.1 离线推荐系统的设计思路

    首先还是要定一个目标,参考所有电商类的产品,实时的推荐系统已经算是一个标配,那么我们的目标就是做一个实时的推荐系统,但目前的情况是我们还没有推荐系统,一步到位做到实时推荐系统还是有些难度。

    那么第一阶段目标是设计一个离线的推荐系统,可以做到隔天推荐,第二阶段可以基于这个离线的推荐系统进行改造做成实时推荐系统。

    推荐系统最核心的地方是召回算法的选择,在刚开始搭建推荐系统时可以选择一些经过验证的、逻辑清晰、运营稳定的找回算法。

    笔者所在公司做电商产品,于物品的协同过滤、基于商品内容的推荐算法都比较适合电商产品,一些大型的电商巨头如亚马逊、淘宝也都在使用,方向一般不会错误。

    7.2 离线推荐系统的算法选型

    实际项目中用的第一个召回算法是基于物品的协同过滤。

    推荐系统系统最基础的算法是基于用户的协同过滤和基于物品的协同过滤,这是标配。

    上文也讲到了这两个算法的优缺点,电商产品还是比较适合基于物品的协同过滤,基于物品的协同过滤最核心的原理是是如果大多数人买了商品A的同时又买了商品B,那么我们就可以向买了商品A的用户推荐商品B。

    实际项目中用到的第二个召回算法是基于商品分词的算法。

    整体思路是先基于用户的历史行为数据找出用户可能喜欢的商品,将商品名称通过ES搜索引擎进行分词操作,并且给每个分词进行打分,然后通过分词搜索商品库中能够匹配到的商品,搜索引擎会自动给出匹配的分数。

    比如一个用户喜欢的商品名称为:秋冬新款韩版破洞宽松长袖T恤,分词后就可以得出用户偏好的分词如秋冬、新款、破洞、宽松等,在通过这些分词在商品库中搜素就能得到可能和秋冬新款韩版破洞宽松长袖T恤相似的商品。

    这种推荐方式也属于内容推荐的一种,实现较为简单。

    在冷启动的情况下会用到保底算法,实际项目用到的保底算法是基于商品的热度的模型。

    定义了商品近60天的销售指数,从商品的浏览人数,加购人数,收藏人数分别赋予不同的权重,用来计算商品的热度。

    对于一个新用户或者各种召回推荐算法并没有算出用户感兴趣的商品,可以基于用户的品类偏好在热销商品中筛选出基于用户偏好的热销商品。

    如果无法确定用户的偏好,可以直接推荐热销的商品给用户。

    接下来是排序算法的选择。

    每个召回算法都会计算出用户感兴趣的商品,那么这些召回算法推荐出来的商品,我们把那些商品推荐给用户呢?上文已经讲到既然每个地方出来的状元都相互不服,那么我们不如再统一进行一次入学考试,通过考试的成绩再统一决定,让那些商品推荐给用户。

    推荐的最终目的是让用户浏览我们的商品,最理想的是购买我们的商品,第一步是点击,我们只需预测出用户是否会点击我们的商品即可,这个指标叫CTR点击率。

    常见的排序算法有哪些呢?

    1. GBDT(梯度提升决策树)+LR(逻辑回归)
    2. FM(因子分解机模型)

    在这里简单讲一下 GBDT+LR,我们只讲算法的大概意思,不讲具体实现,具体实现可以参考AI算法相关书籍。

    预测CTR需要两个东西:特征和权重。

    特征比较好理解比如一个用户的年龄,地址,一个用户近期浏览过这个品类的的商品几次,加购过这个品类的的商品几次类似等等。

    权重就是一个用户如果浏览过这个品类我们觉得用户40%可能喜欢这种品类,一个用户如果加购过这个品类我们觉得用户60%可能喜欢这种品类,那么用户加购的权重就更大。

    GBDT的具体做法可以这样理解,想象不断对一个用户不断提问:是女用户吗?是的话再问:喜欢毛衣吗?是的话则可以问:喜欢那个价格段的毛衣?

    这种不断提问按照层级组织起来,每次回答答案不同后再提出不同的问题,直到最后得出最终答案:用户对这个推荐会满意吗?这就是GBDT树模型。

    树模型天然就可以肩负起特征组合的任务,从第一个问题开始,也就是树的根节点,到最后得到答案,也就是叶子节点,这一条路径下来就是若干个特征的组合。

    GBDT的好处是自动挖掘用户的特征,得到最佳的特征组合,省去特征工程大量繁琐的过程。

    实际项目中可以找产品线的产品经理和运营一下讨论下推荐方案方案,他们对业务更加了解。

    这个项目我们产品线的同事也提了几个比较好的问题:

    1. 笔者所在公司的电商产品比较特殊,定位快时尚女装,几乎每天都会有上新,上新的产品7天后基本都没有货了,这对于推荐算法来说是很大的挑战。

    我们讨论后的解决方案是针对商品打上新旧款的标识,怎么打上新旧款的标识呢?因为商品都放在专场内,专场都有开始时间和结束时间。

    如果商品所在的专场都是未结束,那么我们会给商品打上新款的标识。

    如果商品都在已经结束的专场,那么我们会给商品打上旧款的标识。

    因为新款一般不会有太多的交易数据,所以基于物品和用户的协同过滤都推荐出很少新款,可以提高基于内容的推荐算法的权重,这样就能找到新款商品。

    2. 处于实际的业务场景,需要加一些过滤条件

    比如下架的商品,用户n天内购买过的商品,我们需要在用户最终的推荐结果中剔除。

    还有一些退货率比较高的商品我们设置了一个阀值,如果退货率超过n%,那么会将这些商品从用户的推荐列表统一剔除。

    3. 考虑商品的上架时间和用户访问高峰期因素

    因为笔者所在公司的商品一般都是早晨10点左右上架一次商品,下午18点左右上架一次商品,中午12点左右和晚上20点左右是用户访问的高峰期。

    如果推荐算法的的计算引擎只在晚上计算,早晨10点和下午18点上架的商品大部分都不能推荐出来。

    这时候需要调整我们的计算调度,也就是在中午12点左右进行一次计算,保证上午10点左右的新品都能出现在用户的推荐列表,在下午19点进行一次计算,保证18点上架的新品也能出现在用户的推荐列表。

    7.3 离线推荐系统开发过程

    接下来可以让数据开发工程师准备推荐算法需要的几类数据,第一个是用户的基础数据如下图2-14所示,此类数据可以用来挖掘用户的特征。

    图2-14用户基础数据

    第二个是用户行为的数据,如下图2-15所示,用户在什么时间对商品有浏览,加购、下单等行为,是召回算法的基础支撑数据。

    图2-15用户行为数据

    第三个是商品相关的数据,如下图2-16所示,比如商品的品类,是否上下架等商品的基础信息。

    可以让算法工程师快速拿到商品的相关信息。

    图12-16商品基础数据

    当算法工程师和数据开发工程师按照找回算法和排序算法完成开发后,就会形成最终用户的推荐结果,一般存储在MYSQL等关系型数据库,通过接口对外提供服务。

    每个用户最终的推荐结果格式如下:

    • 用户ID:用户的唯一标识
    • 商品ID:商品唯一标识
    • 召回算法ID:召回算法的唯一标识,便于统计召回算法的效果
    • 点击率:用户点击的概率,一般是0-1的小数
    • 计算时间:产生推荐结果的时间,一般存储近几次的计算结果

    基于推荐结果的数据,后端开发工程师就可以开发对外的服务接口,具体如下表所示:

    为了完成推荐系统,只有数据中台的团队并不行,还需要产品线的产品经理和运营的配合。

    首先要在产品的功能界面预留一个位置,类似淘宝、京东的猜你喜欢,这个可以基于自己的产品特性来选择位置。

    电商线的产品经理需要协调前后端开发处理推荐位置的前后端开发及埋点开发,前后端开发是调用数据中台的推荐接口,完成推荐功能界面的开发,数据埋点要解决2个问题。

    第一是要知道每个场景,每个算法,每天的交易额。

    当用户加购时,要把场景ID,算法ID,同商品一块加入购物车。

    当用户下单时再将场景ID,算法ID一并加入进货车。

    第二我们要统计每天有哪些用户 访问我们的推荐场景,点击了那些商品,这个针对前端可以做常规的埋点,埋点的做法可以参考第二章数据采集模块。

    有了这些埋点数据就可以计算推荐位每天产生的总交易额,总访问用户数等相关商业指标,也可以通过查看每个算法的准确率,召回率,覆盖率这三个指标,来找到最合适的算法。

    数据中台主要承担算法的开发与推荐接口的开发以及后面推荐系统的数据源分析。

    第三步运营需要配协调UI资源,设计推荐位的LOGO,推荐位背景图等工作。

    推荐系统的方案设计大概需要一周的时间,另外需要3天的时间评审方案,电商线的产品经理针对前后端和埋点的开发大概需要一周的时间,数据中台针对算法的开发大概需要1个月的时间。

    第一个版本预计整体时间需要2个月的时间,其中大概用半个月定整体方案和细节的部分,其他都是各个角色开发的时间。

    7.4 离线推荐系统的测试

    至此推荐系统的整个开发流程就结束了,接下来是推荐系统的测试。

    为了方便测试可以开发一个快速拿到用户推荐结果的界面方面产品和测试去查看数据。

    主要包含三块内容:

    1. 可以快速查询每种召回算法每个用户的推荐结果
    2. 排序算法每个用户的最终推荐结果
    3. 给用户展示的最终推荐结果

    查询推荐结果的功能最好有商品的图片,这样会比看商品名称更加直观,具体界面如下图2-17所示,可以快速筛选某个算法,某个用户在某天的推荐结果。

    图2-17用户推荐列表

    首先要针对召回算法进行测试,召回算法主要测试算法的逻辑是否正确。

    比如基于商品的协同过滤,最核心的原理是买了商品A的人大多数又买了商品B,如果商品B是用户预测点击率最高的商品,那么同时买了A和B的人数应该也是最多的。

    一般来说算法工程师和测试工程师合作完成测试用例的验证,算法工程师按照测试工程师的要求提供数据,测试工程师负责验证算法逻辑的准确性。

    第二步需要对排序算法的结果和用户最终的推荐结果进行测试。

    因为逻辑比较复杂,这两个步骤测试起来就很有挑战性。

    在这里推荐一个简单的方法,项目组可以一起定义几个典型用户比如:

    1. 无用户行为的用户
    2. 有历史行为数据,但是很久没来访问的用户
    3. 有历史行为数据并且最近很活跃的用户

    对于第一种用户来说,可以验证一下此类用户的推荐结是否和冷启动的策略一致。

    对于第二类用户来说虽然有历史行为,但是历史行为的数据已经很久,无法再去利用,基于制定的策略需要验证一下此类用户的推荐结果是否和我们的策略相符合。

    第三类用户可以让算法工程师基于他最近的行为输出他喜欢的商品,然后基于他喜欢的商品核对推荐的商品是否有很大的误差,比如用户喜欢50-100的牛仔裤,我们推荐的结果都是500以上的牛仔裤,那么就有问题了。

    最后还需要对过滤的规则进行测试,比如用户近期买过的商品不能出现在推荐列表,退货、缺货率很高的商品不能出现在推荐列表等规则的测试。

    八、从0到1打造一个实时推荐系统

    本章介绍一下从0到1搭建一个实时推荐系统的全过程。

    先看一下什么是实时推荐系统。

    实时的推荐系统已经成为大厂电商产品的标配,我们拿淘宝举个例子,当用户浏览或者加购一个新的商品,过几秒再刷新推荐模块,立即就推荐出来好多类似的商品。

    还有比如我们在刷抖音,刷今日头条,刷的内容越多,展示的内容就越来越接近我们的兴趣,这些公司是怎么做到以这么快的速度推荐出用户喜欢的内容的呢?

    用户感兴趣的内容有个黄金期的,上文讲的离线推荐系统,因为算法计算任务的限制,第二天才能推荐出用户昨天感兴趣的商品,可能第二天用户看到这个商品,已经失去了兴趣,这时我们就要引入一套实时的推荐算法。

    如下图2-18所示是一个比较典型的实时推荐系统的功能架构:

    图12-18实时推荐系统架构

    第一步是获取用户短时间内的兴趣,比如用户近几次的行为或者近一段时间内的行为数据如浏览、点击、收藏、加购、下单了某些商品,可以把用户近几次会话访问或者点击的商品,缓存在客户端,然后通过实时的消息队列的方式,如开源的kafka,将用户近期访问日志实时的传到推荐服务器,这样推荐服务就可以实时的接收到用户最新的行为数据。

    接下来是计算用户感兴趣的商品,通过设定不同的权重找到用户感兴趣的商品列表。

    假设我们设置的权重是如果用户访问访问了一个商品,这个商品就得1分、收藏一了一个商品得2分、加购了一个商品5分、下单了一个商品得7分。

    假设我们取近5次的用户行为数据,比如一个用户近五次行为数据包含:

    • 访问了二次商品A
    • 收藏了一次商品B
    • 加购了一次商品C
    • 下单一次商品D

    基于用户近5次的行为数据并进行归一化处理后可以得出用户对A/B/C/D的兴趣度分别为:

    • 商品A:2分
    • 商品B:2分
    • 商品C:5分
    • 商品D:7分

    基于这5次行为内的数据可以看出用户比较喜欢商品D和商品C。

    第二步是通过用户感兴趣的商品列表在库中找相似的商品

    这里就需要一套实时召回算法,能在2秒内计算好召回结果,可以通过流计算处理平台如Flink实时计算用户喜欢的商品,由于用户的兴趣数据一直在变化,也需要同时更新召回算法结果集中的商品之间的相似度,从而找到与用户近几次访问或者加购的商品最像似的topN个商品。

    在算法层面基于物品的协同过滤和用户的协同过滤算法不适合用在这个场景,因为复杂度比较高,计算时间比较长。

    作为电商产品,商品的描述有大量的信息包括商品的名称、店铺、品类、价格段,基于这些信息可以做基于品类价格段的推荐算法。

    第一优先级是推荐同店铺、同品类、同价格段的商品,第二优先级是不同店铺、同品类、同价格段的商品,第三优先级是同店铺、同品类、不同价格段的商品,第四优先级是不同店铺、同品类、不同价格段的商品等,这个算法认为品类是第一优先级,价格段是第二优先级,店铺是第三优先级。

    比如基于用户的行为数据发现他喜欢一件毛衣,这时可以推荐给他一件同店铺,价格段差不多的毛衣,如果没有同店铺,价格段差不多的毛衣,则推荐给他不同店铺,价格段差不多的毛衣,就这样可以按照指标的优先级一直排下去。

    比如我们按照以下规则来排序:

    1. 同店铺、同品类 、同价格段的新款 (0.875,1]
    2. 不同店铺、同品类、同价格段的新款 (0.75,0.875]
    3. 同店铺、同品类、不同价格段的新款 (0.625,0.75]
    4. 不同店铺、同品类、不同价格段的新款(0.5,0.625]
    5. 同店铺、同品类 、同价格段的老款 (0.375,0.5]
    6. 不同店铺、同品类、同价格段的老款 (0.25,0.375]
    7. 同店铺、同品类、不同价格段的老款 (0.125,0.25]
    8. 不同店铺、同品类、不同价格段的老款[0,0. 125]

    上文已经得出用户对商品D比较感兴趣,假如与商品D同店铺、同品类 、同价格段的新款有商品E和商品F,可以计算一下商品E和商品F的热度,如果商品E销量比较好,那么商品E的的得分就是1分,商品F的得分就是0.875.

    最终算出E的得分1分、商品F的得分就是7×0.875=6.125。

    按照这种方式可以将用户感兴趣的商品D、C、B、A都进行计算,最后就可以得出一个分数有高到低的实时商品推荐列表,可以基于业务需求,比如TOP50做为候选结果集。

    第三步是要解决离线的推荐结果和实时的推荐结果如何结合的问题。

    最理想的方式是通过上文提到的GBDT+LR排序算法将实时推荐结果和离线推荐结果进行统一排序,但是这套排序算法也是相对来说比较复杂,不能做到几秒内出结果。

    解决方案是我们可以人工定义一下实时推荐和离线推荐的优先级,推荐结果都是分页显示的,有以下几种方式:

    第一种方式是前几页显示实时结果,后面显示离线结果。

    这种方式是默认实时推荐结果的优先级是大于离线结果的,问题是我们耗费了那么多资源来算用户的离线结果,但是却没有得到曝光,因为如果用户前几页都没浏览,后面的页面浏览的几率就比较小了。

    第二种方式可以采用交叉显示的方式,比如第一页一共有10个商品,前3个商品显示实时推荐结果,后面7个显示离线推荐结果,第二页同样如此。

    这种方式实时的推荐结果和离线的推荐结果都有曝光,资源利用率相对来说比较大。

    作者:大码王

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

    万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•?ω•?)っ???!

  • 相关阅读:
    AT4144[ARC098D]Donation【Kruskal重构树,dp】
    YbtOJ#643机器决斗【贪心,李超树】
    P3273[SCOI2011]棘手的操作【线段树,并查集】
    AT3950[AGC022E]Median Replace【贪心,dp】
    P3760[TJOI2017]异或和【树状数组】
    AT4505[AGC029F]Construction of a tree【构造题,hall定理,网络流】
    Ybt#452序列合并【期望dp】
    AT3949[AGC022D]Shopping【贪心】
    AT4995[AGC034E] Complete Compress【树形dp】
    P4338[ZJOI2018]历史【LCT】
  • 原文地址:https://www.cnblogs.com/huanghanyu/p/13559592.html
Copyright © 2011-2022 走看看