00:00
呃,我们继续把这一部分基于营语义模型的离线推荐,把它做完,大家会看到我们接下来已经拿到了这个模型,现在是要做预测评分了,对不对?那预测评分我们首先是需要一个什么东西呢?大家会想到是不是首先是需要一个空的矩阵啊呃,前面说到就是user和movie的一个空矩阵,对不对?诶这里边我们可以定义一个叫做user movies,它等于什么呢?是不是就是我们前面提到的用user r DD和movie r DD做一个D卡机啊,啊可以用这种方式来实现一个空矩阵,所以user r dd.s movie r DD那这一步我们的。含义是呃,计算user和movie的笛卡尔机。
01:03
得到一个空平分矩阵对不对,因为平分矩阵它的维度就应该有对应的u ID mid对吧,我们现在其实就是u ID mid都有了,就差填评分了,那那大家会想到这个填评分的时候怎么填呢?六。呃,大家会想到就是模型是不是已经现成啊,调用model的,他会有一个方法叫predict的方法,我们要做的事情当然是针对他要做预测评分,对吧?预测评分最后得到的应该是一个呃,Predict ratings这样的。大家会想到他,他得到的肯定是这样的一个就是RDD的一个列表,对不对,我们看到model.predict是不是有这个,刚才大家可能看太快,大家没看清楚啊,我们直接点过去看一下predict的方法里边是不是可以诶这里怎么是Java派,刚才应该点错了啊。
02:18
啊,我们先把后面的这个内容先先传进去吧,刚才我们,诶大家看啊,这个parameter可以传什么呢?是不是可以单独把一个user和一个product,就u ID midd是不是传进去啊,可以单独传,也可以怎么传呢?啊,当然也可以传这个Java pair r DD对吧?我们当然不用这个还可以传,哎,是不是直接可以传一个,大家看到一个RDD对不对,直接把这个u ID midd构成的这个元组,然后这样的一个RDD把它传进去,所以我们现在是不是就传的是第刚才看到的第三种这种形式啊,直接把它传进去,是不是就就可以得到它的结果是什么呢?是不是还是一个RDD啊。
03:01
那么它的里边的每一个元素是不是就变成了rating类型,这是ML lab里边定义好的rating类型,对吧?哎,大家要把这个要搞清楚好,预测出来,评分已经拿到了,那接下来我们是不是就可以真正的把user Rex这个推荐列表计算出来了,这个列表。基于什么呢?肯定就是基于我们的,对吧?啊,那这个我们首先做一个什么什么计算啊,啊,大家可能会想到,那我们可能一开始可能就先做一个filter吧,呃,比如说我们是不是首先评分应该大于零啊,啊,这个大家是能想到的啊,我就把它全回收过来吧,那评分是哪一项呢?大家会想到里边是不是有user product rating3项,其中的rating是不是就代表评分第三项啊,大于零,我们要求它大于零。
04:07
过滤出评分大于零的。然后filter出来之后,那显然大家会想到我们接下来是不是用户的推荐列表是不是应该基于UID去做一个聚合呀,做一个group by对吧?那首先我们是不是应该把它map一下,Map成前边是一个UID,后边是另外的一个元组对不对?那后边那个元组是不是就应该是像我们前面定义好的recommendation这样的一个mid对应一个score啊,诶这最后把这个聚合起来,他的这个列表是不是就是recommendation的列表啊,这就符合我们最后要的这个数据类型,好,那这里做一个map。
05:01
呃,Map map。当然大家可能习惯的还是。呃,我我这里就不要去做模式匹配了,直接把RA1改就完了,对不对?每一个rating是不是可以转化成,转化成什么呢?里边想要的前面是rating点啊,这里是每一个评分,我们叫做rating,然后大家看到是不是RA,里边它又包含三个元素啊,User product RA对不对?前面我们把user取出来,这是不是UID啊,后边是不是把它再包成一个元组,前边是product,这是不是mid,后边就是我们的评分是不是ra.ra啊。对吧?啊,这个rating是代表我们里边的每一个元素啊,然后它本身是一个大写的这个ML lab里边rating类型,所以里面还有三个元元素,它的第三个元素本身就叫RA,对不对,所以有一个ra.ra大家搞清楚就可以把这个做完map之后,我们就可以是不是group by key了。
06:11
直接group by key选出来,是不是就按照这个UID去把它做了分组聚合啊,那得到的结果大家会想到再做一个map,这个是不是就跟我们这个统计推荐这里边,我们最后拿到的这一步非常类似的啊。大家看是不是这里把这个拿出来之后,我们构建的就是刚刚的那个东西啊。前面一个东西,后面一个元组对不对,然后green,呃,Group by Di k选出来之后,剩下的这一组是不是构建成我们想要的那个数据类型啊,所以这都是类似的一些操作,所以我们还是用一个模式匹配UID对吧,那后边那个我们就叫Rex吧。然后做什么操作呢?是不是要把它转成我们最后想要的定义好的这个样例类,是不是叫user xx,这是我们最后想要的这个数据结构,对不对,然后它的第一项是不是就是UID啊,啊,这个没问题啊,后边是不是要把这个rax本身它的这一组这个列表我们要做一个转化,转化成。
07:25
哎,前面提到的那个recommendation类型的列表啊,而且我们可能还想对它做个排序对不对,我们还要截取前多少个,我们前面是不是定义了一个常量叫这个max recommendation啊,对吧?所以我们是不是要截取这20个啊,诶,那大家想到这个做法是不是就跟统计推荐那个里边的top ten是一一模一样啊啊,这个就完全没区别,所以还是把它拿出来之后,这是一个raps,它本身是一个,呃,这个拿出来是一个RDD,对吧?所以我们这里边把它to list,然后是不是就可以调呃,South这个方法了,对不对?那么south with里边是一个布尔类型的一个表达式,我们给入的是按照哪个值哪个元素来做判断,来做排序,对吧?我们是根据哪个呢?
08:19
哦,大家会想到这后边的这个这个元素啊,它里边的每一个值是不是都是这样的一个元素啊,我们要根据后面的第二个元素对吧?RI,好,同样这里写的是大于第二个元素对不对?这就表示按照第二个元素降序排列好,那之后是不是应该去选里边的前20个,是不是take啊?我们既然已经定义了这个常量了,那还是把它引入进来吧,是不是user maps recommendation啊,最后是不是应该把它做一个map转换成我们想要的,想要的数据结构,每一个元素是不是要转换成一个叫做recommendation的这个类啊,这个对象对吧?里边第一个元素是不是就是X的一。
09:13
Mid传过来对不对?第二个元素是不是就是X的二啊,大家想是不是这样,所以这样就是跟前面的这个统计推荐非常的类似,我们就把它转换成了自己想要的一个数据结构,呃,那当然了,按照呃,我一般的习惯都是把它转成这个data frame对吧?啊,转成data frame之后,我们是不是直接可以把它存到mongo里边去了啊,当然这里边我们可能很简单,就只有这么一个表的话,我就不用再把那个专门提一个方法出来了,大家想用刚才的那个提出来的方法也可以,对不对?我这里边就直接写吧。比如说这个我要写的是user ras,是不是调用这个data frame writer里边的write方法对吧?呃,Data frame的write方法返回的是一个data frame writer对不对?好那。
10:09
Right方法可以给对应的option啊,这个大家都已经写熟了啊,Uri给什么呢?是不是mango config里边的uri啊,然后点option。呃,D collection对吧,这个应该往哪个表里边写呢?定义好的常量是不是user xx。然后下边我们可以定义这个mod,既然是写入,我们一般用的都是overri对吧?呃,最后format一下。com.mongo DB spark.cq最后是不是点save啊,哎,所以大家看这样就把我们想要的数据写入到mango里边去了,好,这一部分就做完了,当然,呃,大家看就是,尽管这个做法很简单,那里边的想法整体的思路跟之前的是比较一致的,是因为跟之前比较一致,所以我们看起来就比较简单,对吧?呃,其实我们的核心就是说根据模型已经训练好的模型找出它的这个预测评分,那么这个predict到底要传什么样的数据,我们就给它准备好,对吧,传进去这个空矩阵传进去,然后基于拿到的。
11:35
预测评分,我们做一个筛选,然后构建成自己想要的数据类型,然后把它按照评分做一个排序,对不对,提取前20,这就完事了,好,然后最后我们大家看,做到这一步的话,我们的。推荐是不是已经做完了呀,对吧,用户的推荐列表就已经得到了,所以如果要是说基于英语翼模型的协同过滤推荐,这就已经完成了,非常简单。当然我们还有另外一个任务没有没有做,就是我们说的一个副产品,我们是不是基于得到的这个模型里边的电影影特征,电影特征矩阵可以算每每两个电影之间的相似度啊,算出这个相似度来之后,我们要把它存起来,为之后的实时推荐做基础,所以这里边我们再把这一部分做一个实现,呃,那大家会想到我们一开始应该要拿什么东西。
12:31
我们要算这个相似度,首先要拿什么?是不是首先先得拿特征啊,对,就每一个电影的特征我们应该拿出来,那从哪里拿呢?对,肯定还是从模型里面拿,对不对?我们定义一个叫movie features这样一个东西,它从哪里拿呢?Model大家看有一个是不是有一个product features这样一个属性啊,这是不是就代表大家看它的类型是什么?
13:00
是一个RD对吧,里边是一个元组,一个int,然后是一个double类型的array,那所以大家会看到这里边代表什么呢?是不是它的每一个特征都是一个double类型啊,然后后面构成了一个数组,对不对,那这样的一个数据类型,好那么我们把它直接引入进来,这里我们要对它做一个处理,为什么呢?因为大家想到我们之后是不是想要对它的那个double类型的那个数据,我们想要做。相似度计算啊,如果想要做相似度计算,我当然我们也可以不转,那就直接用double类型的数据,就是一个一个去算,对不对,稍微会比较死板一些,那如果说我们把它做一个转化转成什么呢?转成大家看啊。我们这里还是做一个模式匹配啊case,每一个mid对应的会有一个features,我们把它转换成mid后边的这个features,我们把它创建一个double matrix。
14:14
大家看这就,诶这个double matrix在哪里有,大家一看这个已经出来了,对不对,是不是就是在g plus里边有啊对吧,矩阵运算,线性线性代数计算对吧?那么它把这样的一个数组传进去,就可以创建一个double matrix类型的一个对象,那么这个对象有什么好处呢?等一会儿我们做这个相似度计算的时候,大家就会发现。那个实现非常简单,好,那么这一步我们先把它做出来,然后接下来大家会想到我们要算这个两两电影之间的相似度对不对,那最后我们是不是诶类似的一个想法,我们因因为最后得到的那个矩阵相似度矩阵跟我们的这个用户推荐列表其实很类似,那大家可以想到我用户推荐列表,我的思路是每一个user跟每一个MOVIE22匹配,对吧,匹配起来之后,然后根据那个评分做一个筛选,然后最后把想要的这个数据结构弄出来,那我这里是不是也是相当于可以把对两个电影两两匹配做一个笛卡耳机,然后最后根据什么条件做一个筛选,最后把它包装成我们想要的数据结构就就可以了呀,啊,所以这里的实现我们就都按照这个套路来比较简单的啊,呃,那大家会想到我们最后要拿到的是一个叫做movie res的一个东西。
15:42
那么它应该等于什么呢?是不是movie features,他要做一个笛卡尔机,跟谁做呢?Movie features。我们就是所有的电影跟所有的电影两两之间要比较对不对,那所以是不是自己跟自己做一个第二机啊,哎,所以大家看是这样的一个做法啊,就是全外连接的这种方式,Movie features做完这个,哎,我们看啊。
16:13
两呃对所有电影两计算他们的呃相似度,先做一个笛卡尔机对吧。这是我们这一步的含义,那做完笛卡耳机之后啊,当然我们就可以去做一个filter了,对吧,那大家会想到在这个笛卡尔机我们筛选出来之后,它是不是两两自己跟自己做了笛卡尔机,那是不是每一个电影也会跟自己配对配起来啊。那大家会想自己跟自己求相似度应该算出来是多少啊啊,百分之百一对不对,算相似度那个余弦算出来是不是肯定是一啊,哎,那大家会想到这样是不是不太合理啊,哎,你为什么能算出来一个就是相似度是一的东西,结果你发现相似度很高,我就推出来了对不对,结果一发现是自己啊这这显然不合理嘛,那我们一开始筛选是不是应该把自己筛掉啊,自己跟自己的匹配筛掉对吧?好,那么我们用什么方式去筛呢?大家会想到我这里做一个case模式匹配A和B,它俩是不是匹配起来之后,一个是A,一个是B啊这两个都是一个特征向量,那么把它呃怎么样呢?呃,大家会发现我们是不是按照它的m mid去做一个判断,如果mid相等,这俩就不要了,对吧,所以我们要求的是,哎,注意这里我们返回的是一个条件对吧,那我们返回应该是它俩相等的条件吗。
17:55
那就成了把相等的选出来了对不对?哎,我们是不是要不相等啊,对,所以那A的什么呢?A点哦,大家会想到我们这里边的feature,它刚才大家记得这个feature拿出来是什么是吧?它是不是一个m mid后边跟的是一个数组啊啊,我们现在是把这个数组转换成了一个double matrix对不对,所以现在我们是选这个midd呢,还是选后面数组呢?对,我们选的是一对吧,那么A的一是不是就不能等于B的一啊,对,所以这是我们的这个关律条件。
18:34
首先我们要把这个把自己跟自己的配对过滤掉,这是这一步。好,过滤过滤完了这个之后,接下来我们应该就可以跟根据他们两个的那个第二个元素是不是那个,呃,它的特征向量啊,根据特征向量是不是就可以算它的余弦相似度了,好,接下来我们继续map。
19:05
Map,那大家想到同样的啊,这里A和B我们拿到的话做一个什么操作呢。大家会想到我首先是不是应该算一个鱼线相似度啊,这个看起来好像不太好算,我定义一个叫做same cor的一个相似度的评分same score对吧?然后我去调用一个啊,那我得定义一个函数了,我得定义一个叫cons same这样一个函数,呃,现在还没定义,等一会我们来定义对吧?那大家想到我这里要给它传进去的是什么呢?两个向量的相似度,是不是要把两个向量传进去啊,那这里的向量是什么?A的对A的下划线二第二个元素,B的下划线二第二个元素对吧?哎,我们先把这个算出来,然后我们最后map完了之后要返回一个什么东西呢?
20:06
哎,大家会想到我们是不是应该把,哎,现在的这个,我们最后想要的是一个什么东西,是A的mid,然后是不是B的mid,还要有它们之间的一个相似度啊,而且最后我们是不是应该根据某一个电影前面的这个mid,然后要做聚合对不对?把它所有相似的都选出来对不对?哎,所以我们现在最后返回这样的一个数据结构,那就是A的一,这是不是A的midd,然后后边我们把它包装成一个元组,那里边就是B的一,对吧,Midd,然后后边是什么呢?对,后边是不是上面算出来的这个相似评分啊,呃,Same score,好,那最后呃,大家知道这个放在最后一行,这就是返回对吧?好,那么我们得到这个东西之后还可以做什么事情呢?
21:06
嗯。做完了这个之后,大家会想到得到的所有的这个相似度,那我们或许还可以再筛选一下,因为我们最后可能不不按照排序把前几个选出来了,那我们直接筛选,诶我们是不是可以筛选大于多少的一个相似度的,所有的都拿出来啊,啊比方说我们这里给一个filter条件,大于0.6的都拿出来,那这个这个怎么写呢?诶,每一个元素的对是不是第二个啊,大家会看到啊,这是第二个元素,是不是后面这个元素啊,所以是不是还得对,再找到它的第二个元素,是不是就是里边的这个评分,诶大家这个都看的没问题啊,然后大于0.6,如果大于0.6的话,我们就把它筛选出来对不对,哎,Filter出来这里。
22:02
过滤出相似度大于0.6的,好,呃,那么把这个filter完了之后,我们就可以是不是可以做group by了,Group by key是不是就根据前面的这个mid把它筛选,就是做了一个聚合啊,分组了,对吧?然后最后是不是还是要把得到的结果包装成我们想要的结果结果啊mid。呃,然后这里边我们可以对应到上面这个Rex对不对?里边这应该是一个啊,大家如果看这个Rex觉得不舒服的话,我们还是叫items吧,这就是我们前面聚合起来的,呃,一组数据对不对?一组项,那么它里边的每一个元素是不是都应该是有这样的两项啊,对吧?有,有这样的两项对不对?好,那么我们要把它转成什么结构呢?我们是不是要把它转换成定义好的样例类,是不是movie ras啊,这是最后我们要写入到mango里边的相似度列表,对吧?那movie ras第一个参数是不是就是mid,所以mid还是保留,然后大家想到那后面是不是还是一样啊,还是一样,我们可以那个I items是不是可以to list,然后就可以salt with,对不对啊,我们可以对它。
23:36
做一个排序,按照大小排序,那是不是这里我们要用到的是哪一个,大家想到这里边的每一个啊,大家想到肯定是下划线二对不对,每一个里边都是它的对余弦相似度大于下划线点下划线二对不对啊,Thought with,然后我们是不是可以把它啊,这就不用再take了对不对,因为前面我们已经选了大于0.6的了,对吧?然后我们直接再做一个map map是不是把它转换成最后想要的recommendation类型啊,啊,这操作就跟前面完全一致啊,Recommendation X点下划线一,X点下划线二啊,这就是我们整个的这个过程啊,当然了,在这个过程当中大家可能发现就是,呃,这里边还报了很多错,对不对?那是因为我们这里边这个还没实现,对不对,诶我们这里有问题吗。
24:44
去做to list to list之后。这里是吗?这个应该是没什么关系啊,好,我我们先看一下,先把这个实现,大家看一下还有没有错对不对,如果要是没错的话,那肯定就没问题了,接下来多了括号吗?看一眼啊,Recommendation,这是map对吧。
25:12
大于号,这里是最后得到的这个,呃,Movie Rex应该是对的,对吧,少少括号了吗?大于。然后这个是吧,对,好,我们先把那个上面的那个相似度求解,相似度的这一部分先实现对吧?呃,那大家想一下这个本身的这个相似度矩阵,诶这一部分如果我们后面继续写的话,是不是还应该把它to df要做一个转换啊,转换成这个之后,是不是就是上面类似的这个模式,我们直接把它写到mango里面就完事啊,啊这其实我们都都抄下来啊,这个没什么区别,这里是movie RA,诶movie ras。
26:02
哇,这个好慢啊,然后我们这里把这个改过来movies,呃,其他的都不需要改,我们直接写进去就可以了,对吧?好,接下来我们把这个函数来实现一下,我们这里边要做的是求向量余弦相似度。好,那么我们这里边定义一个Co cos。哦,有点慢啊,大家会看到这里边默认传入进来的是不是就是一个double matrix啊,对吧,我们前面是不是已经把它转换成了double mettricx,好,那么然后这里边我们把这个matrix改一个名字吧,我们叫MOVIE1好了,MOVIE1这里叫MOVIE2对吧。
27:04
然后我们这个有没有返回值啊,这个就不是空了,它是不是应该有返回值啊,返回对,大家会想到这里返回值我们是要存到这个,诶去哪了,我们是要把它放到这个same score里边,对不对,所以它应该有一个double类型的返回值,好然后等于我们去做一个实现,那么大家看一下这里边怎么去实现呢?哎,直接MOVIE1。它是不是要跟MOVIE2求余弦相似度的话,分子上是它俩做点乘啊啊,如果是double matrix的话,我们不用一项一项去算,直接有一个点dot方法。那大家看这是不是就代表点乘,Other里边传入的是不是也是另外一个double mettrix啊,所以MOVIE2他俩做点乘,这就是我们的分子,那大家会想到分母是不是它俩的模长的乘积啊好,那么MOVIE1的模长怎么算呢?大家看可以有NORM1NORM2,这代表什么?L1范数,L2范数对吧?之前跟大家讲过是不是L2范数就是它的模长对不对,向量模长,所以我们直接用这个就完事了,后边是不是还要乘以movie比二的弄二啊啊,当然我们这一部分应该是得括起来算的对吧?大家看就这么简单搞定了完事。诶上上面好像错也都没了,对不对?就是这儿的问题。
28:41
所以大家看这个看起来复杂,实际实现起来是不是非常简单啊,对吧?结果大家没做之前感觉好像很复杂,但是我们引入这个j plus里边的double matrix这个对象之后会发现,诶,就这么这这还真是跟Python一样,照着那个公式抄下来就完事,对不对啊,所以这个还是比较好使的啊。
29:04
好了,那这部分代码就完全实现了,我们同样还是来运行一下,看一下效果怎么样。
我来说两句