程序员的自我修养
Home » Apache Spark, 机器学习 » Spark MLlib之协同过滤

Spark MLlib之协同过滤

30条评论25,364次浏览

什么是协同过滤

协同过滤(Collaborative Filtering, 简称CF),wiki上的定义是:简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐使用者感兴趣的资讯,个人透过合作的机制给予资讯相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选资讯,回应不一定局限于特别感兴趣的,特别不感兴趣资讯的纪录也相当重要。

以上定义太拗口,举个简单的例子:我现在多年不看日本anime的新番了,最近突然又想看几部新番,但又不知道这么多新番中看哪些比较好,于是我就找几个同样喜欢日本动漫的朋友来咨询。我第一个想咨询的朋友是和我口味最像的,我们都特别喜欢看《虫师》、《黑之契约者》、《寒蝉》这样的小众动画;我问的第二个朋友和我口味差不多,他特别喜欢看《钢炼》《无头骑士异闻录》这样的动画,我虽然喜欢,但不像他那么喜欢;由于身边喜欢日本动画的朋友不多,剩下第三个可以咨询的是一个宅女,平常经常看腐、宅、基的动漫,完全跟我不是一路人,于是问了下她推荐的片子,并将这些片子打上的黑名单的标签。然后我就开始看第一个朋友推荐的片子了,要是时间特别多又很无聊我可能会看第二个朋友推荐的,但打死我也不会看第三个朋友推荐的。这就是协同过滤的一个简化、小众版。

如何进行相似度度量

接着上面的例子,我可以通过我和其它朋友共同喜欢某个或某类动漫来确定我们的口味是否一样,那么如何以数学或者机器的形式来表示这个“口味一样”呢?通常,是通过“距离”来表示,例如:欧几里得距离、皮尔逊相关度、曼哈顿距离、Jaccard系数等等。

欧几里得距离

欧几里德距离(Euclidean Distance),最初用于计算欧几里得空间中两个点的距离,在二维空间中,就是我们熟悉的两点间的距离,x、y表示两点,维度为n:

\(d(x,y)=\sqrt {(\sum_i^n (x_i-y_i)^2)}\)

相似度:

\(sim(x,y)={1\over {1+d(x,y)}}\)

皮尔逊相关度

皮尔逊相关度(Pearson Correlation Coefficient),用于判断两组数据与某一直线拟合程度的一种度量,取值在[-1,1]之间。当数据不是很规范的时候(如偏差较大),皮尔逊相关度会给出较好的结果。

\(p(x,y)={{\sum {x_iy_i}-n\overline{xy}}\over {(n-1)S_xS_y}}={{n\sum {x_iy_i}-\sum x_i\sum y_i}\over{\sqrt{n\sum{x_i^2}-(\sum x_i)^2}{\sqrt{n\sum{y_i^2}-(\sum y_i)^2}}}}\)

曼哈顿距离

曼哈顿距离(Manhattan distance),就是在欧几里得空间的固定直角坐标系上两点所形成的线段对轴产生的投影的距离总和。

\(d(x,y)={\sum{\|x_i-y_i\|}}\)

Jaccard系数

Jaccard系数,也称为Tanimoto系数,是Cosine相似度的扩展,也多用于计算文档数据的相似度。通常应用于x为布尔向量,即各分量只取0或1的时候。此时,表示的是x,y的公共特征的占x,y所占有的特征的比例:

\(T(x,y)={x\bullet y\over{\|x\|^2}+\|y\|^2-x\bullet y}={\sum{x_iy_i}\over{\sqrt{\sum{x_i^2}}}+\sqrt{\sum{y_i^2}}-\sum{x_iy_i}}\)

计算推荐

根据上述“距离”的算法,我们可以找出与自己“口味一样”的人了,但这并不是目的,目的是找出推荐的物品。一种常用的做法是选出与你兴趣相同的N个人,然后根据这N个人的记录来进行加权推荐。具体如下,假设已经计算出欧几里得相似度:

朋友 相似度 银魂 S.x银魂 食灵零 S.x食灵零 雨月 S.x雨月
A 0.95 10.0 9.5 9.0 8.55 - -
B 0.80 8.5 6.8 7.5 6 5.0 4
C 0.25 - - 6.5 1.625 9.0 2.25
总计 16.3 16.175 6.25
Sim.Sum 1.75 2 1.05
总计/Sim.Sum 9.31 8.09 5.95

其中,S.x开头的表示相似度与评分的乘积,Sim.Sum表示打过分的朋友的相似度之和。可以看出根据三位友人的推荐,我从这三部动漫中应该选择银魂来看。

Item CF与User CF

基于用户的协同过滤(User CF),其基本思想相当简单,基于用户对物品的偏好找到相邻邻居用户,然后将邻居用户喜欢的推荐给当前用户。上述过程就属于User CF。

基于物品的CF(Item CF)的原理和基于用户的CF类似,只是在计算邻居时采用物品本身,而不是从用户的角度,即基于用户对物品的偏好找到相似的物品,然后根据用户的历史偏好,推荐相似的物品给他。

两者的计算复杂度和适用场景皆不同,详细可参见参考资料。

Spark协同过滤实现

训练数据

其中第一列为userid,第二列为movieid,第三列为评分,第四列为timestamp(未使用)。

完整版下载:MovieLens(解压后的u.data文件)。

代码实现

运行结果

参考资料

(转载本站文章请注明作者和出处 程序员的自我修养 – SelfUp.cn ,请勿用于任何商业用途)
30条评论
  1. 张三说道:

    你好,有学习价值,但是代码不全哦,如rating -> new T...、以及(line -> {....等

  2. 张三说道:

    你好,推荐列表如何出了?

    • yurnom说道:

      有环境的话跑一下,结果一目了然的

      • Alexandra说道:

        “This is effectively confiscating part of their wealth in order to advance someone else’s idea of better tao1l.&#822t;sney this isn’t true. when the land was upzoned around the denny triangle, lot values tripled. upzoning doesn’t make land less valuable, it does the opposite, generally. unless it’s done in places that don’t make sense.

  3. 张三说道:

    你好,小弟初学spark,有不少问题,能否加你QQ,有问题可以请教请教,邮箱:meiboqi@126.com

  4. 张三说道:

    或者可否把您的这些示例的源码发我一份,供学习学习~

    • yurnom说道:

      上面贴的就是全部源码了。。数据下载链接也有。。我的idea连不上github,所以暂时无法共享出来。。抱歉。等过几天能连上时候我传上去给你

      • Maggie说道:

        Hiya MariaThank you so VERY much for all that you have done for PASIC especially over the last few months, you have been phenomenal!So many more people know about PASIC now and I am sure that will mean that we get more support than ever.If you count up all that you have raised for PASIC since you’ve known about us I am pretty sure that it would exceed £23,000 and that’s a huge achievement in an;eon&#8217ys books.Perhaps you can slow down a little now and get your life back! LOLLuvnhugsBea

  5. 李四说道:

    上面写的是基于相似度的 协同过滤算法,后面实现 是als算法是 基于矩阵分解的。

  6. 匿名说道:

    你好,请问不使用java8的话,代码怎么写

  7. jchubby说道:

    你好,代码中用的是ALS算法,我想请问一下,ALS是UserBase还是ItemBase的协同过滤?

  8. TTT说道:

    rank is the number of latent factors in the model.
    rank是干嘛的

  9. 匿名说道:

    你好我想问一下要运行您的程序,用eclipse可以吗,需要配置什么jar包吗

  10. 匿名说道:

    JavaPairRDD usersProducts = ratings.mapToPair(rating -> new Tuple2(rating.user(), rating.product())); 写法有问题
    换了Function 不支持maptopair了

    • Trudy说道:

      Omenirea merita un pumn in mecla ca sa-si revina. Nu mai putem continua in stilul asta pazairtar de a suge resursele planetei. Ne omoram gazda sau cel putin asa credem, planeta poate oricand sa scape de niste paraziti ca noi.

  11. 匿名说道:

    Rating 的x,y超过Int的最大值,怎么办?
    我的x=19891349869

  12. sunddenly说道:

    你好能共享一下代码吗

  13. 匿名说道:

    你好,受益匪浅,刚学spark,能否加你,以后有什么问题请教您。我qq1246296864

  14. 匿名说道:

    UserSideCF这个类在哪里

  15. 匿名说道:

    部分程序已经无法使用, 另外 你的import代码 也应该放上来哈

  16. 匿名说道:

    那个 user的推荐结果楼主查看了么? 为什么输入数据 最高是五分,输出结果都是7分8分啥的?

  17. 匿名说道:

    请问一下,那个 user的推荐结果楼主查看了么? 为什么输入数据 最高是五分,输出结果都是7分8分啥的?怎么设置输出的分数的最大值?

发表评论给匿名


profile
  • 文章总数:81篇
  • 评论总数:241条
  • 分类总数:32个
  • 标签总数:45个
  • 运行时间:1253天

大家好,欢迎来到selfup.cn。

这不是一个只谈技术的博客,这里记录我成长的点点滴滴,coding、riding and everthing!

最新评论
  • Anonymous: :?: :razz: :sad:
  • Anonymous: 牛
  • Anonymous: 楼主你好,我偶尔也会 遇到Reconnect due to socket error: java.nio.channels.ClosedCha...
  • Anonymous: sdfs
  • Anonymous: :arrow: :neutral: :cry:
  • Anonymous: java.io.NotSerializableExcepti on: DStream checkpointing has been enabled but the DStreams with their...
  • wick: HI,请问一下,U,S,V得到 ,怎么得到近似矩阵 (用spark java),谢谢。
  • Michael Whitaker: Thank you for this blog, it was very helpful in troubleshooting my own issues. It seems that no...
  • Anonymous: :mad:
  • Anonymous: :???:
  • Anonymous: :mad: :mad: :mad:
  • 洋流: 哥们,我问个问题,你 把testOnborrow去掉了。。 如果得到的jedis资源...
  • 洋流: 哥们,我问个问题,你 把testOnborrow去掉了。。 如果得到的jedis资源...
  • Anonymous: :razz: :evil: :grin:
  • 张瑞昌: 有很多,比较常见的是 Jacob迭代法,一次迭代O (n^3),迭代次数不清楚 ...
  • Anonymous: :mrgreen:
  • lc277: 你好 我想问下一般删除节点 要多久,要删除的datano de大概用了1t,解除...
  • Anonymous: 你好 我想问下一般删除节点 要多久,要删除的datano de大概用了1t,解除...
  • Anonymous: :smile: :grin: :eek:
  • 李雪璇: 想要完整代码,可以帮 忙发给我吗