基于用户的协同过滤算法—推荐关注的用户
简介:
基于用户的协同过滤算法很早就出现了,是推荐系统最古老的最著名的算法,1992年被提出并用于邮件系统过滤,之后很久也一直被业界广泛的使用。什么叫做基于用户的协同过滤算法呢?简单来说就是把和你在同一个兴趣圈子里的人的爱好推荐给你。比如说:你加入了一个文艺青年阅读的圈子,那么意味着你和圈子里的人都有着相同的阅读兴趣,如果你那天想看一本新书,有不知道看哪些书,那么这个圈子里的人推荐你一本《生命不能承受之轻》,你发现这本书你没有看过,而且正好还符合你的阅读口味,其实通过用户推荐物品的行为,就叫做基于用户的协同过滤算法。
什么时候使用推荐系统:
需求的数据信息过载。
没有明确的选择目标。
比如你选择一首好听的歌,首先新歌老歌各种风格的歌曲库十分丰富。你现在只是想听一首歌,确并不知道听那首歌,如果确切知道那首歌直接就可以通过搜索引擎选出来。如果你关注的一个朋友在听一首新出来的歌,那么把这首歌推荐给你,很有可能是你喜欢的风格。
推荐系统带来的巨大利益
亚马逊的前科学家Greg Linden在他的博客里说过,在他离开亚马逊的时候,亚马逊至少有20%的销售来自于推荐算法。此外亚马逊的前首席科学家Andreas Weigend在斯坦福曾经讲过一次推荐系统的课,据听他课的同学透露,亚马逊有20%~30%的销售来自于推荐系统。
就在我购买《推荐系统实践》这本书的时候,推荐系统同时推荐了另外一本相关的书,看了下简介也很感兴趣,咬牙一起买了,看这就把点击率有效的转化为购买行为了。
算法原理
实现基于用户的协同过滤算法主要包括两个步骤:
找到与目标用户兴趣相似的用户集合
找到这个集合中用户喜欢的、并且目标用户没有听说过的物品推荐给目标用户
首先寻找和用户兴趣相契合的用户集合,这里我们主要用到2个公式来计算两个用户的兴趣相似度。
jaccard公式:
余弦相似度公式:
这里N便是集合,u,v分别表示两个用户的感兴趣的人或物的集合。
其次,根据以上公式得到用户的兴趣相似度后,UserCF算法会给用户推荐和他兴趣最相似的K个用户喜欢的物品。
如下公式计算用户u对物品i的感兴趣程度:
rvi 表示用户 v 对 i 的喜欢程度,在本例中都是为 1,在一些需要用户给予评分的推荐系统中,则要代入用户评分。
实例讲解:
本文将基于之前的博文《使用C#+Jumony开发网络爬虫并对数据做相关分析》
使用爬虫爬取的 伯乐在线 网站的用户信息实现。
数据实体:
- 用户,使用网站主页URL地址作为唯一标识
例如:用户:唐小娟,主页URL地址为:http://www.jobbole.com/members/ tangxiaojuan/
- 该用户的关注人,目前爬虫只取主页有的关注用户,其他更多关注用户没有获取。
实现过程:
1.初始化用户数据加载,并输入相关的参数。
源码如下:
Console.WriteLine("初始化数据"); MyUsers = new List<User>(); InitUser(); Console.WriteLine("数据准备完毕..."); Console.WriteLine("请输入推荐人数:"); int needCount = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("请输入用户名,URL地址名"); string nameUrl = Console.ReadLine(); nameUrl = nameUrl.TrimEnd('/'); User user = MyUsers.Where(s => s.Url.Contains(nameUrl)).FirstOrDefault(); if (user == null) { Console.WriteLine("未查到此用户!"); Console.ReadLine(); return; }
2.计算所有用户和输入用户的相似度,并排除掉相似度等于0的用户。
在本次实例代码中采取的是Jaccard公式来计算相似度的。
源码如下:
int writeInId = user.Id;//准备推荐人 //计算所有用户和输入用户的相似度,并排除掉相似度等于0的用户 List<UserSorce> userSorces = new List<UserSorce>(); foreach (var item in MyUsers) { if (item.Id == writeInId) continue; UserSorce userSorce = new UserSorce(); //使用Jaccard公式计算兴趣相似度 double numerator = user.Interest.Intersect(item.Interest).Count(); //排除交集等于0的 if (numerator <= 0) continue; double denominator = user.Interest.Union(item.Interest).Count(); if (denominator == 0) continue; double mark = numerator / denominator; userSorce.Id = item.Id; userSorce.Name = item.Name; userSorce.Url = item.Url; userSorce.Interest = item.Interest; userSorce.Sorce = mark; userSorces.Add(userSorce); } if (userSorces.Count <= 0) Console.WriteLine("无合适的推荐"); userSorces = userSorces.OrderByDescending(s => s.Sorce).ToList();
3.选取n个相似度最高的用户,分别计算出用户的感兴趣程度,按大小排序输出。
源码如下:
//选择最相似的n个用户 Console.WriteLine("=========================="); Console.WriteLine("与该用户关注最相似的" + needCount + "用户如下:"); List<string> interests = new List<string>(); for (int i = 0; i < needCount; i++) { UserSorce u = userSorces[i]; Console.WriteLine("No." + (i + 1) + " 相似度[" + userSorces[i].Sorce.ToString("F4") + "]" + ":"); Console.WriteLine(u.Name + "(" + u.Url + ")" + Environment.NewLine); if (u.Interest.Count() == 0) continue; if (interests.Count() == 0) interests = u.Interest; else interests = interests.Union(u.Interest).ToList(); } Console.WriteLine("=========================="); //已经关注的用户 List<string> IsFollowerUsers = user.Interest; //加上用户本身 IsFollowerUsers.Add(user.Url); //所有相似度最高的用户关注的人 List<string> exceptInterests = interests.Except(IsFollowerUsers).ToList(); if (exceptInterests.Count <= 0) Console.WriteLine("无法推荐感兴趣的人!"); List<InterestStar> stars = new List<InterestStar>(); foreach (var interest in exceptInterests) { double value = 0; double depth = 1;//感兴趣的程度 //推荐人 string recommendUser = String.Empty; for (int i = 0; i < needCount; i++) { User u = new User(); u = MyUsers.Where(s => s.Id == userSorces[i].Id).FirstOrDefault(); if (u.Interest.Contains(interest)) { recommendUser += "[" + u.Name + "]"; double sorce = userSorces.Where(s => s.Id == u.Id).FirstOrDefault().Sorce * depth; value += sorce; } } InterestStar star = new InterestStar(); var mUser = MyUsers.Where(s => s.Url.Contains(interest)).FirstOrDefault(); if (mUser == null) star.Name = interest; else star.Name = mUser.Name + "(" + mUser.Url + ")"; star.StarSorce = value; star.RecommendUser = recommendUser; stars.Add(star); } stars = stars.OrderByDescending(s => s.StarSorce).ToList(); int starIndex = 1; Console.WriteLine(Environment.NewLine + "=========================="); Console.WriteLine("推荐用户感兴趣的人:"); foreach (var item in stars) { if (starIndex > needCount) break; Console.WriteLine("No." + (starIndex++) + " 感兴趣程度[" + item.StarSorce.ToString("F4") + "]" + ":"); Console.WriteLine("感兴趣的人:" + item.Name); Console.WriteLine("推荐的人有:" + item.RecommendUser + Environment.NewLine); } Console.WriteLine("=========================="); Console.WriteLine("结束"); Console.ReadKey();
测试结果如第一张图所示。
GitHub项目地址:https://github.com/zuiyuewentian/Recommend.git
注:本文参考项亮编著的《推荐系统实践》一书。
文章评论