[推荐算法]基于用户的协同过滤算法

news/2024/9/16 19:02:28/

转自:http://blog.csdn.net/ygrx/article/details/15501679

什么是推荐算法


推荐算法最早在1992年就提出来了,但是火起来实际上是最近这些年的事情,因为互联网的爆发,有了更大的数据量可以供我们使用,推荐算法才有了很大的用武之地。

最开始,所以我们在网上找资料,都是进yahoo,然后分门别类的点进去,找到你想要的东西,这是一个人工过程,到后来,我们用google,直接搜索自己需要的内容,这些都可以比较精准的找到你想要的东西,但是,如果我自己都不知道自己要找什么肿么办?最典型的例子就是,如果我打开豆瓣找电影,或者我去买说,我实际上不知道我想要买什么或者看什么,这时候推荐系统就可以派上用场了。

推荐算法的条件


推荐算法从92年开始,发展到现在也有20年了,当然,也出了各种各样的推荐算法,但是不管怎么样,都绕不开几个条件,这是推荐的基本条件

  • 根据和你共同喜好的人来给你推荐
  • 根据你喜欢的物品找出和它相似的来给你推荐
  • 根据你给出的关键字来给你推荐,这实际上就退化成搜索算法了
  • 根据上面的几种条件组合起来给你推荐

实际上,现有的条件就这些啦,至于怎么发挥这些条件就是八仙过海各显神通了,这么多年沉淀了一些好的算法,今天这篇文章要讲的基于用户的协同过滤算法就是其中的一个,这也是最早出现的推荐算法,并且发展到今天,基本思想没有什么变化,无非就是在处理速度上,计算相似度的算法上出现了一些差别而已。

基于用户的协同过滤算法


我们先做个词法分析基于用户说明这个算法是以用户为主体的算法,这种以用户为主体的算法比较强调的是社会性的属性,也就是说这类算法更加强调把和你有相似爱好的其他的用户的物品推荐给你,与之对应的是基于物品的推荐算法,这种更加强调把和你你喜欢的物品相似的物品推荐给你。

然后就是协同过滤了,所谓协同就是大家一起帮助你啦,然后后面跟个过滤,就是大家是商量过后才把结果告诉你的,不然信息量太大了。。

所以,综合起来说就是这么一个算法,那些和你有相似爱好的小伙伴们一起来商量一下,然后告诉你什么东西你会喜欢。

算法描述


相似性计算

我们尽量不使用复杂的数学公式,一是怕大家看不懂,难理解,二是我是用mac写的blog,公式不好画,太麻烦了。。

所谓计算相似度,有两个比较经典的算法

  • Jaccard算法,就是交集除以并集,详细可以看看我这篇文章。
  • 余弦距离相似性算法,这个算法应用很广,一般用来计算向量间的相似度,具体公式大家google一下吧,或者看看这里
  • 各种其他算法,比如欧氏距离算法等等。

不管使用Jaccard还是用余弦算法,本质上需要做的还是求两个向量的相似程度,使用哪种算法完全取决于现实情况。

我们在本文中用的是余弦距离相似性来计算两个用户之间的相似度。

与目标用户最相邻的K个用户

我们知道,在找和你兴趣爱好相似的小伙伴的时候,我们可能可以找到几百个,但是有些是好基友,但有些只是普通朋友,那么一般的,我们会定一个数K,和你最相似的K个小伙伴就是你的好基友了,他们的爱好可能和你的爱好相差不大,让他们来推荐东西给你(比如肥皂)是最好不过了。

何为和你相似呢?简单的说就是,比如你喜欢macbook,iphone,ipad,A小伙伴喜欢macbook,iphone,note2,小米盒子,肥皂,蜡烛,B小伙伴喜欢macbook,iphone,ipad,肥皂,润肤霜,C女神喜欢雅诗兰黛,SK2,香奈儿,D屌丝喜欢ipad,诺基亚8250,小霸王学习机那么很明显,B小伙伴和你更加相似,而C女神完全和你不在一个档次上,那我们推荐的时候会把肥皂推荐给你,因为我们觉得肥皂可能最适合你。

那么,如何找出这K个基友呢?最直接的办法就是把目标用户和数据库中的所有用户进行比较,找出和目标用户最相似的K个用户,这就是好基友了。

这么做理论上是没什么问题的,但是当数据量巨大的时候,计算K个基友的时间将会非常长,而且你想想就知道,数据库中的大部分用户其实和你是没有什么交集的,所没必要计算所有用户了,只需要计算和你有交集的用户就行了。

要计算和你有交集的用户,就要用到物品到用户的反查表,什么是反查表呢?很简单,还是是上面那个AB小伙伴和C女神的例子,反查表就是喜欢macbook的有你,A,B,喜欢iphone的有你,B。。。就是喜欢某些物品的用户,有了这个表,我们就可以看出来,和你有关系的用户就只有A和B,D了,而C女神和你没有任何交集,所以不用去想C了。

这样,我们有了A和B,D,然后就分别计算A和B,D与你的相似度,不管用哪个相似性公式,我们算出来都是B和你更相似(在这个例子中,一般会用Jaccard来计算,因为这些向量不是特别好余弦化),但如果此时我们的K设定为2,那么我们就得出了与你最相邻的基友是B和A。

这就是与目标用户最相邻的K个用户的计算。

通过这K个用户来推荐商品了

好了,你的好基友我们也算出来了,接下来要向你推荐商品了。但是我们可推荐的商品有小米盒子,note2,蜡烛,润肤霜,肥皂这么四种,到底哪种才是你需要的呢?这里的算法就比较广泛了,我们可以不排序,都一股脑推荐给你,但这明显可能有些你不怎么感兴趣,我们也可以做一些处理,假如我们算出来A和你的相似度是25%,B和你的相似度是80%,那么对于上面这些产品,我们的推荐度可以这么来算

  • 小米盒子: 1*0.25 = 0.25
  • note2: 1*0.25 = 0.25
  • 蜡烛: 1*0.25 = 0.25
  • 润肤霜: 1*0.8 = 0.8
  • 肥皂: 1*0.8+1*0.25=1.05

这样就一目了然了,很明显,我们会首先把肥皂推荐给你,这个可能是你最需要的,其次是润肤霜,然后才是蜡烛,小米盒子和note2。

当然,你可以把上述结果归一化或者用其他你觉得合适的方式来计算推荐度,不管怎么算,推荐度还是得和基友与你相似度有关系,就是那个0.8和0.25一定要用上,不然前面白算了。

算法总结

好了,通过这个例子,你大概知道了为什么会推荐肥皂给你了吧,这就是基于用户的协同推荐算法的描述,总结起来就是这么几步

  1. 计算其他用户和你的相似度,可以使用反差表忽略一部分用户
  2. 根据相似度的高低找出K个与你最相似的邻居
  3. 在这些邻居喜欢的物品中,根据邻居与你的远近程度算出每一件物品的推荐度
  4. 根据每一件物品的推荐度高低给你推荐物品。

比如上面那个例子,首先,我们通过反查表忽略掉了C女神,然后计算出A和B,D与你的相似度,然后根据K=2找出最相似的邻居A和B,接着根据A,B与你相似度计算出每件物品的推荐度并排序,最后根据排好序的推荐度给你推荐商品。

怎么样,是不是很简单啊。

算法存在的问题


这个算法实现起来也比较简单,但是在实际应用中有时候也会有问题的。

比如一些非常流行的商品可能很多人都喜欢,这种商品推荐给你就没什么意义了,所以计算的时候需要对这种商品加一个权重或者把这种商品完全去掉也行。

再有,对于一些通用的东西,比如买书的时候的工具书,如现代汉语词典,新华字典神马的,通用性太强了,推荐也没什么必要了。

这些都是推荐系统的脏数据,如何去掉脏数据,这是数据预处理的时候事情了,这里就不多说了。

来个实战的吧


说了这么多,肥皂也推荐了,那么我们来点实际的,我这里下载了movieLens的数据集,至于这个集合是什么大家google一下,反正很多地方用来做测试算法的数据,这个数据集里面有很多用户对于电影的打分,我们的需求是随便输入一个用户,然后根据协同算法,给他推荐一些个电影。

由于用户给电影打分有好有坏[1到5分],而我们上面的例子中都是说的喜欢某件物品而没有说不喜欢的情况,所以首先,我们要把数据处理一下,简单的来做,我们可以认为3分以上的话代表这个用户喜欢这个电影,否则就是不喜欢,这样显得有点太死板了,我们也可以这么来定义,比如用户A对30部电影打分了,首先求出他打分的平均值,然后高于这个平均值的我们觉得用户喜欢这个电影,否则认为他不喜欢。

好了,用户的喜欢与不喜欢的问题解决了。下面就可以开始算法了,代码不全贴出来了,贴个流程吧,具体代码可以去看我的github

 
  1. #读取文件数据
  2. test_contents=readFile(file_name)
  3. #文件数据格式化成二维数组 List[[用户id,电影id,电影评分]...]
  4. test_rates=getRatingInformation(test_contents)
  5. #格式化成字典数据
  6. # 1.用户字典:dic[用户id]=[(电影id,电影评分)...]
  7. # 2.电影用户反查表:dic[电影id]=[用户id1,用户id2...]
  8. test_dic,test_item_to_user=createUserRankDic(test_rates)
  9. #寻找邻居
  10. neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]
  11. #计算推荐列表
  12. recommend_dic={}
  13. for neighbor in neighbors:
  14. neighbor_user_id=neighbor[1]
  15. movies=test_dic[neighbor_user_id]
  16. for movie in movies:
  17. if movie[0] not in recommend_dic:
  18. recommend_dic[movie[0]]=neighbor[0]
  19. else:
  20. recommend_dic[movie[0]]+=neighbor[0]
  21. #建立推荐列表
  22. recommend_list=[]
  23. for key in recommend_dic:
  24. recommend_list.append([recommend_dic[key],key]
  25. recommend_list.sort(reverse=True)

对于随便输入一个用户,我们得到以下这个推荐结果

 
  1. movie name release
  2. =======================================================
  3. Contact (1997) 11-Jul-1997
  4. Scream (1996) 20-Dec-1996
  5. Liar Liar (1997) 21-Mar-1997
  6. Saint, The (1997) 14-Mar-1997
  7. English Patient, The (1996) 15-Nov-1996
  8. Titanic (1997) 01-Jan-1997
  9. Air Force One (1997) 01-Jan-1997
  10. Star Wars (1977) 01-Jan-1977
  11. Conspiracy Theory (1997) 08-Aug-1997
  12. Toy Story (1995) 01-Jan-1995
  13. Fargo (1996) 14-Feb-1997

多输入几个用户你就会发现,像Titanic,Star Wars这种超级热门的电影,只要你选的这个用户没看过,推荐系统就一定会推荐给你,这就是我们前面说的脏数据,实际系统中这种数据是需要处理掉得。我们这篇文章只做算法讲解,就不去管这些东西了。


http://www.ppmy.cn/news/622328.html

相关文章

【毕业设计】基于单片机的太空游戏机 - 嵌入式 物联网 stm32 51

文章目录 1 简介2 主要器件2.1 硬件器件 3 实现效果4 设计原理4.1 器件连接 5 部分实现代码6 最后 1 简介 Hi,大家好,这里是丹成学长,今天向大家介绍一个学长做的单片机项目 基于单片机的太空飞机游戏机设计与实现 大家可用于 课程设计 或…

视频融合平台EasyCVR电子地图增加鼠标悬停展示经纬度

EasyCVR可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等,以及厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等,能对外分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。平台可…

计算机网络—数据链路层

文章目录 数据链路层服务差错编码多路访问协议信道划分随机访问MAC协议 数据链路层服务 该层中的帧数据结构: 帧头部会因为不同的局域网协议而不同,因此会在另一篇博文中继续介绍不同的帧数据报,不在本博文介绍。(不过除了PPP协…

python实现图片拼接

# -*- coding:utf-8 -*- # 图片拼接 import PIL.Image as Image import os, sys mw 256 # 图片大小 toImage Image.new(RGB, (25171, 11802))#构造图片的宽和高,如果图片不能填充完全会 #出现黑色区域 for y in range(47):#0-46for x in range(99):#0-98fname &q…

C/C++ 图片拼接

注意CV::Mat dst(height,weight)顺序 // TODO 1 merge frame(background)/face(tmp_ptr->frame) into one imagecv::Mat background;cap.read(background);cv::Mat dst(720,1280,CV_8UC3,cv::Scalar(0));//黑底cv::Rect rect_face(0,0,640,720);cv::resize(tmp_ptr->fra…

numpy数组做 图片拼接(concatenate、vstack、hstack)

两种方法拼接 #img np.vstack((img, img2)) # vstack按垂直方向,hstack按水平方向 img np.concatenate((img, img2), axis0) # axis0 按垂直方向,axis1 按水平方向统一图片大小,保证数组维度一致避免拼接失败。 把图片全部调整成第一…

基于python的多张不同宽高图片拼接成大图

半年前写过一篇将多张图片拼接成大图的博客,是讲的把所有图片先转换为256256的图片后再进行拼接,今天看到一个朋友的评论说如何拼接非正方形图片,如4757,之前有个朋友也问过这个,我当时理解错了,以为是要把不同尺寸的照片如3245、5675等拼接成大图,当时还纳闷,那不是很…

OpenCV 纵向、横向拼接图片

👨‍💻个人简介: 深度学习图像领域工作者 🎉总结链接: 链接中主要是个人工作的总结,每个链接都是一些常用demo,代码直接复制运行即可。包括: &am…

Python实现将多张图片拼接为一张

文章目录 一、需求二、代码 一、需求 将多个这样的图片进行拼接为一张 拼接效果: 更多照片张数同理 二、代码 import PIL.Image as Image import osIMAGES_PATH img\\test\\ # 图片集地址IMAGES_FORMAT [.png, .jpg] # 图片格式 IMAGE_SIZE 224 # 每张小…

Python之多张图片拼接

参考:https://www.jianshu.com/p/9a4739420c9e 在做图像处理时,线阵相机采集保存的图片高度不够,需要将多张图片拼接在一起,原图片大小是20481024,需要将三张纵向拼接,形成大小为20483072的图片。话不多说…

Unity 图片拼接中间有空隙问题详解

有一种美,叫对称美。对称随处可见,从皇城庙宇到民宅轩榭,对称之美,美在庄重。项目中,我们常常会遇到一些对称的图片,但是为了节约资源,往往我们会选择将其分成两半,只取其一&#xf…

R语言可视化——图片拼接排布(一)

目录 0引言1、customLayout包1.1 主要函数介绍1.2主要函数讲解1.2.1 lay_new1.2.2 lay_show1.2.3 lay_bind_col1.2.4 lay_split_field 1.3案例一1.4案例二 2、总结 0引言 在之前使用R语言拼接图片,一般的图形用的是par函数,ggplot2的拼接使用的是gridEx…

python - 图像处理 - 图片拼接和堆叠

业务说明: 此示例脚本作用,包含方法和逻辑:图像读取,图片尺寸读取,重置图片大小,图片等比缩放,图片拼接,图片覆盖与堆叠(子母图) 图片展示: 单…

CTF图片拼接

CTF图片拼接需要的工具有montage和gaps,找了大量的博客终于成功了。 montage在python的库里可以下载,所以下载指令为: pip install montage 但是我一直爆pip的依赖错误,搞半天没成功过,但是我在linux的apt的安装库里…

使用python将任意张图片拼接成多张大图

今天看到在之前的一篇博客下有位朋友留言提到了“将多张图片拼接成多张大图”的问题,这一系列的博客已经写了三篇了,这是第四篇了,后三篇全都是基于广大博友的热心提问而成型的,十分感谢各位的关注,让我们一起进步吧~~~ 先放上之前的三篇吧,都是姊妹篇: 1.使用pyth…

阿里图片合成接口拼接

上篇博客我写了把两张图片合成为一张图片。 那样的合成方式是可以的,也是可以合成成功的。但是这样的合成方式有些许不足 1、合成的图片除非服务器端给配置的图片考虑到了不同设备的分辨率的情况,这对不同的设备给了不同的图,如果不是这样&am…

ENVI拼接图片

ENVI CLASSIC可以根据两张图片的经纬度信息进行拼接 MapMosaickingGeoreferenced

前端使用canvas拼接多张图片

应业务要求,要把使用canvas截取的app每一屏的图片拼接在一起。图片的地址存放在一个log文件中。 先了解一下drawImage() 方法: drawImage() 方法在画布上绘制图像、画布或视频。 drawImage() 方法也能够绘制图像的某些部分,以及/或者增加或…

python切割、拼接图片

在做智能识别方面的时候遇到了一些瓶颈,即对于一张清晰度足够高,目标却很小时,识别的效果不是很好。 这时可以首先将图片分割成3*3,一共九张图片,分别进行识别之后再进行图片的拼接。 首先是图片的分割,将图…

Vue 中对图片地址进行拼接

拿到一组数据&#xff0c;其中的img地址是这样的 我们想要将它转化为正常的图片地址&#xff0c;需要使用for循环来将图片拼接起来 getSingList(){getSingerList().then((res) >{if (res.codeERR_ok){this.singersres.data.listconsole.log(this.singers)for(var i0;i<th…