00:00
别的地方其实整体架构都差不多,大家思路应该也比较清晰,我们主要对还是涉及到这个算法里边来,怎么样去呃,算它的这个铜线相似度呢,那这里边其实核心其实是要统计,是不是要统计评分的个数啊,对吧,就是一个商品有多少个人给他评过分,这是一个评分的个数,然后呢,我们还要算两个商品同时给两个商品评分过的人数又有多少个,而且是两两商品我们都得算一下,那这个感觉还是有点麻烦的啊,那我们的思路当然就是说先去统计每一个商品它有多少人评分,这个是比较简单的啊好,第一步啊,我们。统计每个商品的评分个数。好,所以我们第一步其实是统计每个商品的评分个数,呃,那么我们这里面怎么去做呢?因为已经有了data frame,其实我们可以很简单的用data frame的,对吧,按照。
01:16
Product ID。来做,呃,大家可以看一下这个现在data frame相关的这些API,这些操作方法啊,其实转换起来是非常容易的,那我们定义一个叫做product。RA count df,它可以用我们之前的RADF做一个计算,可以直接group by,对吧?来可以看,它可以直接针对某一列去做group by,那么这里的这个列我们根据哪个去做呢?对,Product ID。
02:01
然后后边诶,大家看是不是直接可以count啊,所以直接就可以得到这样的一个count的结果啊,后边这里面是none,这里边我们先把它注掉,看到这个报语法错误啊啊,那大家可能会感兴趣,就是说这个得到的又是一个什么东西呢?Count之后。Count得到的就是一个data frame,所以大家看就是data frame,整个这个操作流程其实就是一个流式的这种,就像就是frame的API,它的思路就是什么呢?就是构建一个流失操作的pipeline,对吧,就像管道操作一样,一个一个都得到的,接下来得到的都是data free,呃,如果大家不知道他长什么样的话,我们看一眼吧啊。先跑一下,看一看后面stop了是吧,好,大家看程序已经跑完了,我们看一眼得到的是什么东西呢?这个data frame其实就得到的是product ID和两个列,也就是每一个product对应的count把它得到了,呃,那所以大家会发现我们这里边其实呃,可能不仅仅是需要这样的一个一个数据,我们应该是还想把就是原来的那个数据都拿出来,对吧,对应的那些评分数据都拿出来,所以接下来。
03:32
第二步去做一个处理。可以在原有的。原有的评分。表上就是对吧。三。添加。Count这一列啊,那么大家会想到我怎么样去添加count这一列呢?非常简单,其实前面这是一个data frame。
04:07
这也是一个data frame,我是不是直接可以做一个对,直接可以做一个join,把它内连接起来来得到的,是不是就可以把这个count追加到我们对应的那个product ID后面去啊好,然后接下来我们就会得到一个叫做RA,这就是with。Count df。我们用谁来join应谁呢?啊对,我们应该用RADF去join后边,为什么呢?因为RA里边是不是product ID不止出现一次啊,因为他有可能是很多人给很就是给同一部电影,呃,不是电影啊,就是商品对吧?呃,很多人给同一个商品去做过评分,所以我们这里边product ID可能会出现多次,那我们其实是对每一个出现的那一次评分,都应该把它总共的那个评分数添加到后面,这是它的一个属性,所以应该是用。
05:15
RADF去join后边的product count df。呃,那那大家会想到这个本身的这个状意应该是什么状意呢。对,大家会想到本来默认的这个参数是不是就应该是inner drawing啊,对吧,所以我们这里边本身就是一个inner drawing啊,然后后边指定这个join的column名字,我们根据什么来join呢?对,还是product ID把它去添加进来。呃,然后接下来我们做什么事情。接下来就比较关键了,我们已经得到了每一个商商品它的评分的个数,它的个数就是相当于我们在算同线相似度的这个公式里边,下边这两项是不是都可以得到了。
06:07
关键是上边对,就是他们之间的那个交集,怎么算呢?啊,对,但是会想到这我们其实是得在里边去选取同时对他们有过评分行为的那个user,然后统计那个个数,才能够得到他们之间的,呃,就是这个交集对吧?呃,他们评分人数的这个交集,那这一步怎么去做呢?对,那可能大家会想到我得对那个user ID去做group by,但是你直接group by的话不行,对吧?所以我是不是还得去做一个join,怎么join呢?就是把两两之间,两个评分之间去做一个join,就把我们的评分表去做一个join。
07:03
Draw引起来,按照什么draw应呢?用user ID去做draw。所以大家想到按照user ID把评分表自己跟自己照,用起来是不是得到的后边就是同一个用户。评分过的两个商品。呃,我们只是把两个表做join,就自己跟自己做做join,那是不是就是同一个用户评分过的两个商品啊。呃,大家可以想象一下这个状态,我们先写出来,然后大家看一眼就应该知道了,呃,那接下来我们要做的就是将评分按照用,按照用户。ID22配对。呃,那最后我们是要统计被同一个用户。
08:01
评分过的。呃,就是统计两个商品。被同一个用户评分过的次数,对吧?这是我们的一个目的,所以我这里可以定义一个,比方说叫join的DF,他是做什么事情呢?就是用我们前边的RA with point df自己跟自己做一个join。呃,然后我们按照哪一个去做join呢?对,用这个user ID去做一个join,那这里大家可能会有点呃,搞不太明白到底是个什么东西,那大家看一下这个状语出来是个什么东西吧。照应的DF对吧,再跑一下看看。呃,这里计算完成,大家看一下我们的运行结果是什么样的呢?照应的DF里边是什么样的。
09:00
User ID,最前面这是join的K对吧,后边就是product ID score count,第一个元素的第一个商品的这个信息放在这里,然后后边是不是就是第二个商品的信息啊。它相当于就是把我们本身reading with point这个表,这张表里边的每一行都跟自己里边的每一行去做了一个配对的匹配,按照什么原则匹配呢?是不是就是UID相同?UID相同的这两个商品是不是就代表了?就是同一个用户对这两个商品都做过评分啊,哎,所以大家会想到在这个里边,我们统计他的个数,是不是就得到的就是。呃呃,那那大家想我们接下来要统计个数,应该统计什么呢?是不是得按照这个这两个product ID对,把他们两个合在一起作为K去group group by得到的所有的那个用户user ID的个数,就是我们同时对他俩做出评价评分的用户的个数。
10:12
呃,所以接下来我们是得做这个操作。那当然了,大家看着这个有点不顺眼,因为这两个表名是不是给的一样啊,名字是一样的,所以我们在上边再做一些别的操作,呃,首先我们把它转换成一个data frame对吧?呃,先user ID。呃,然后后边是product,呃,我们就叫PRODUCT1吧,就知道他肯定是ID啊,然后后边是SCORE1对,然后COUNT1,呃,当然了,后边我就直接复制吧,后边就都是二对吧,COUNT2 score2 product2,呃,然后大家会想到最后其实我们用到的应该是什么呢?其实就是product ID,这两个product ID拿到,然后我们按照他们作为K去做聚合统计user ID是不是就可以啊?
11:18
啊,当然了,这两个count其实也应该保留一下,为什么呢?因为我们最后算的时候从这里边直接拿出来也方便计算对不对?呃,所以呢,我就把这个score都去掉就可以了,但是大家如果看到这一步的话,其实score就没什么用,我一开始就把它去掉也可以,对吧?啊,所以如果前面没去掉的话,我们在这里再去select一下是不是就可以了,那这里边只要。只要我们想要的内容,把它叫做。User ID,然后后边是product id1,呃,PRODUCT1 count1 product2count2,只要保留这五项就可以了,有了这个东西之后,我们去创建一个临时表去写CQ去查询吧,因为接下来这个ID,这个联合查询可能就有点麻烦了,对不对?所以我们去写一条CQ去做吧,前面我们也同样都可以去写CQ啊。
12:13
好,所以那么创建一个join的DF,可以去create or replace temple view,这里边我们就叫做join的吧。创建一张。临时表。用于写SQL查询。那接下来有了这张表之后,我们就希望干什么,按照什么做。对,按照I。
13:10
然后我们希望的是统计user ID的数量,对不对?就是。对两个商品同时评分的人数啊,或者说次数对吧,评分的次数,这里边我们写了一条CK。呃呃,大,大家这里看到了,我们其实选取出来的时候没有自己过滤掉自己对吧?呃,这里是相当于第一条选取出来就是自己跟自己就就匹配在一起了,所以大家会想到如果前边没有过滤的话,我们是不是到最后,因为大家想到最后我肯定会拿出来一个统计列表,就是推荐列表嘛,我到最后把自己的那个ID去筛掉是不就完事了啊,其实也是可以去做的啊,好,所以这里边我们去呃写一条CQ,那么得到的这个东西应该是一个同线。
14:14
跟同线相似度相关的有有同线的统计对吧,同线次数的统计,所以我把它叫做Co,呃呃,Occurrence。就是铜线啊,Co occurrence df,等于对我们写一条出去。呃,那么呃,这这条CQ可能会稍微的麻烦一点,我们写成这样的格式吧,呃,大家看就是可以用这样的多行的字符串来写这条CQ对不对啊,最后它以这个竖线作为每一行以竖线作为起始,最后有一个这个strip Mar,然后就可以把它转换成我们想要的这个CQ啊,然后select什么呢?最后想选取出来的内容应该是。
15:07
首先这个product id1和product id2肯定是需要的,对不对,诶,这里边我们把它呃to df的时候叫做的是PRODUCT1啊,我们就按PRODUCT1就可以了,PRODUCT1,然后对逗号product。二这是我们首先要拿出来的两个ID,对吧,然后后面还需要什么东西呢?对,是不是需要count一下user ID啊对,这个我们把它叫做,呃,叫做同线的那个次数,我们叫做Co count吧。然后大家还会想到,我是不是还应该拿出来COUNT1和COUNT2啊,那聚合之后的COUNT1COUNT2我直接选,大家想我们做过分组之后的那个COUNT1COUNT2,是不是他应该一组里边都一样,我直接是不是直接选取第一个就可以了,First count1as count1first。
16:13
COUNT2 count2。那当然了,后边我们要from join前面创建出来的临时表对不对,然后接下来。呃,需要做什么不要忘记对吧。什么对PRODUCT1PRODUCT2是不是这样一条CQ做完就可以了,当然这个计算的过程当中,大家如果觉得呃性能可能会有问题的话,我们可以直接给他做一个catch啊。好,那么这样得到的结果,那么这个扣currentr df里边的结果其实就是PRODUCT1PRODUCT2,这是我们对应的那个ID对吧,然后后边这是不是就是那个铜线的次数。
17:04
对应我们的公式是不是就是上面这个分子啊,然后分母是它俩的各自出现的次数的乘积,在开根号是不是就是COUNT1COUNT2,做这个计算就可以了,所以大家看现在我们所有需要的东西都已经有了,接下来就算。做转换应该能够,诶这里边是不是我们就应该能够得到这个SIMDF了,根据这个前面的这一部分就可以得到DF。他去做一个map操作啊,呃,那大家会想到这里边我的每一行里应该能够拿到这几个参数,我最后希望得到的是什么呢?最后是不是希望得到的是一个?
18:01
是不是应该是一个它里边的第一个ID,然后我我们最后包装成的是不是一个product ID,然后后面跟着111个他的那个相似度列表啊,所以前边是不是还是ID1放在前面,诶,所以他的ID1怎么拿呢?啊,当然我们这里面可以get s,也可以get int,你如果要get int的话,这里是不是应该传那个它它那个角标啊,对吧,这里是零对那后边。大家会想到我是不是把后边的这个列表每一个元素包装成一个元组,二元组,那么又是第二个product ID,然后跟着的应该是那个。相似度的值对不对,相似度的那个值,所以我这里边给的应该是肉点get int1,这是我的product ID对吧。
19:00
那么后边跟着的应该是它的相似度值,我这里边叫Co car occurrence吧,我定义一个叫做这样的一个东西,所以是不是前面我应该把它算出来啊,定义一个这样的东西把它算出来啊扣。Currency啊,那么这个怎么去计算呢?那那我还是重新定义一个函数吧,这个看起来好像不是特别容易计算啊,Co of currentr SIM,这里边需要传入的就应该是对,大家会想到是不是前面我们这里边的这个Co count,还有COUNT1 count23个参数传传进去我们套公式就完事了,哎,那这里边Co count怎么取呢?呃,这里大家要注意啊,这个Co count是什么数据类型?我们去取肉点get as对吧?Count它是什么数据类型呢?大家注意这里边的count,我们是不是用count把它做做出来计算啊,对CQ里面的count,它返回的是一个long,好,然后后边一样是不是肉点get as我们要取出来COUNT1啊,那COUNT1是什么呢?
20:25
COUNT1也是前面count出来的,是不是也是一个浪啊,哎,所以这里边它是一样的东西啊,好,那同样我们后边还应该有一个COUNT2。把它同样也筛选出来,传进到这个函数里边,计算出对应的铜线相似度,我们就可以直接按照这种格式把它返回了,对吧?呃,这个这里其实就是。提取需要的数据。
21:00
包装成对,最后我们需要的这个product ID,然后这里是product id1,对不对,然后里边是product id2,后边是对应的一个score这样的一个格式,对不对?呃,还是包装成这样,然后接下来呃操作其实就大家也应该非常熟悉了,我们在offline里边其实对应的都做过类似的计算啊,就是得到它的,呃,我们是怎么算的,得到这样的一个形式之后,是不是我们接下来直接可以去filter对吧?然后我们可以去呃做这个BBY,然后按照前面这个做做分组,然后得到的结果是不是把它转换成对应的这个product RA形式啊,这里面其实我们做的这个事情几乎都是完全一样的,呃,那我这里就直接把它copy过来吧。
22:02
哎,不过这里大家要注意的是,我们当时这里算的时候,前面拿到的是什么?呃,就前面拿到的这个数据结构是什么呢?直接做filter的时候,前面拿到的是RDD还是d frame,对,应该是RDD,对吧?所以这里边如果我们直接要套后边那个代码的话,我们是不是先把它转换成RDD啊?然后对应的所有的一切都可以去做计算了,对吧?啊,所以是这样的一个过程,呃,当然了,这个相似度我们可能就不要按照这个0.4去算了,因为我们不知道这个算法算出来大概是多少,我可以把这个删掉,然后group by k就是按照前面的第一个product ID做了一个分组聚合,那么得到的应该是一个product ID,后边跟着一个列表,那么这个列表我们就把它包装成product re的形式。
23:02
具体到里边来看的话,那又是一个product ID对应着的应该是一个呃,就是recommendation的数组,对不对?那这里面大家稍微注意一下,就是我们还当时是提到了一句啊,就是to list之后还应该做什么操作呢?哎,这里面。点不要放在后边啊。我是不是还应该把自己跟自己删掉那个过滤掉啊,不应该把自己也放在里边对不对,那我可以直接在这里边写一个filter去过滤是不是就可以了,那这里边怎么去过滤呢。点future啊。是不是对于每一个?每一个X,我是要求它对这里边的每一个元素,它第一个是product ID,后边一个是score,对吧,我这里就是那个我们的相似度,这里面我是不是要求他的product ID不能等于自己自己是什么,是不是就是前面的product ID,对是这样的一个东西。
24:19
把它做一个计算哦,大家觉得可能更早过滤,这个性能上可能会好一点是吧?呃,但是这个其实没多大区别,因为自己跟自己嘛,就只有那么一条对吧,这个就还好啦,然后后边我们同样根据这个当前的呃,就是第二个元素,也就是说相似度的那个分数,然后去做一个排序,降序排列转换成map输出,那当然大家如果要是说前面定义了这个。对,如果是取多少个的话,对,我可以去take对吧,那我们前面定义了一个叫做max recommendation这样一个常数,直接把它写在这里就可以了,呃,大家看到这里边一直还在报错,因为我们前面这个。
25:08
应该是这个铜线相似度,这个计算还没完成,对不对,那接下来我们还有一个任务,要把这个铜线相似度。呃,大家要先休休息一下吗?还是我们直接一起讲完?就剩下一个套公式,把那个东西做完就可以了,讲完吧,是吧,好。好,那后边我们就DeFine一个。Co occurrence。SIM这样的一个函数,那么它里边的三个参数一个就是。我们定义的这个Co count对吧,共同的这个数量,然后COUNT1COUNT2,它的返回是什么啊,返回是count啊,Count尔啊,它的返回是什么?对相似度应该是个double类型,对这个非常简单。
26:03
这个非常简单,就是一个double类型。那么实现的过程也是非常简单,按照公式是不是直接就是Co count除以除以什么是下面它俩相乘在开根号对吧?对,这里边是这个按照。公式计算同线相似度,所以我们这里边其实就直接调ma里边的SQRT方法求平,那个这个它的开根号对吧?平方根,那么里边COUNT1乘以COUNT2,是不是这样就完事了呀?诶这样就把我们前面的所有的内容都已经完成了,然后这里转换成DF之后保存到mango打开就可以了。啊,我们就可以运行一下,看看它的结果。
27:02
好,大家看我们这里边结果已经算完了,也没有报错,那我们到mongo里边去看一眼,大家看现在的这个表就多了一个叫做item CF product这样一个表,对吧?所以看一眼它里边的数据,呃,find.pretty大家看到其实就是这样的一个列表,跟我们之前定义好的推荐列表,或者说相似度列表是不是完全一样啊对吧?表达形式都一样,一个物品跟它相似的物品按照这个排评分啊给出来,所以大家可以看到这个得分其实对比较小,这是跟我们那个算法相关的,对吧?所以说这个你并不能说它跟那个内容相比,相似度就小啊,这里边大家也可以看一下啊,根据这个item CF看看它能有哪些相似的推荐呢,然后大家看。
28:02
这个相似推荐就多了,因为我们当时只是选取了按照前十个去去截取,对不对啊,这里边而且相似的东西就不光一个鼠标,相似的东西就不光是鼠标了啊,它还可以有什么,可以有耳机,也可以有这个U盘,甚至还有书,大家会想到为什么会有书呢?对,因为用户行为他可能就是买这个,呃,就是评分过鼠标的啊,他就还评分过这本书啊,就是有相相似的这种用户去去做这件事情,所以这里边就真的是可以推出来内容完全不相似的东西,对吧?啊,这就是c item CF这部分内容,大家也可以直观的看到他跟基于内容推荐他们俩之间的差别。
我来说两句