陈程的技术博客

  • 关于作者
全栈软件工程师
一个专注于技术研究创新的程序员
  1. 首页
  2. .NET
  3. 正文

用C#写基于用户的协同过滤算法,推荐网站上你可能感兴趣的人

2016年9月7日 626点热度 0人点赞 0条评论

基于用户的协同过滤算法—推荐关注的用户

简介:

基于用户的协同过滤算法很早就出现了,是推荐系统最古老的最著名的算法,1992年被提出并用于邮件系统过滤,之后很久也一直被业界广泛的使用。什么叫做基于用户的协同过滤算法呢?简单来说就是把和你在同一个兴趣圈子里的人的爱好推荐给你。比如说:你加入了一个文艺青年阅读的圈子,那么意味着你和圈子里的人都有着相同的阅读兴趣,如果你那天想看一本新书,有不知道看哪些书,那么这个圈子里的人推荐你一本《生命不能承受之轻》,你发现这本书你没有看过,而且正好还符合你的阅读口味,其实通过用户推荐物品的行为,就叫做基于用户的协同过滤算法。

什么时候使用推荐系统:

需求的数据信息过载。

没有明确的选择目标。

比如你选择一首好听的歌,首先新歌老歌各种风格的歌曲库十分丰富。你现在只是想听一首歌,确并不知道听那首歌,如果确切知道那首歌直接就可以通过搜索引擎选出来。如果你关注的一个朋友在听一首新出来的歌,那么把这首歌推荐给你,很有可能是你喜欢的风格。

推荐系统带来的巨大利益

亚马逊的前科学家Greg Linden在他的博客里说过,在他离开亚马逊的时候,亚马逊至少有20%的销售来自于推荐算法。此外亚马逊的前首席科学家Andreas Weigend在斯坦福曾经讲过一次推荐系统的课,据听他课的同学透露,亚马逊有20%~30%的销售来自于推荐系统。

就在我购买《推荐系统实践》这本书的时候,推荐系统同时推荐了另外一本相关的书,看了下简介也很感兴趣,咬牙一起买了,看这就把点击率有效的转化为购买行为了。

算法原理

实现基于用户的协同过滤算法主要包括两个步骤:

找到与目标用户兴趣相似的用户集合

找到这个集合中用户喜欢的、并且目标用户没有听说过的物品推荐给目标用户

首先寻找和用户兴趣相契合的用户集合,这里我们主要用到2个公式来计算两个用户的兴趣相似度。

jaccard公式:

余弦相似度公式:

这里N便是集合,u,v分别表示两个用户的感兴趣的人或物的集合。

其次,根据以上公式得到用户的兴趣相似度后,UserCF算法会给用户推荐和他兴趣最相似的K个用户喜欢的物品。

如下公式计算用户u对物品i的感兴趣程度:

rvi 表示用户 v 对 i 的喜欢程度,在本例中都是为 1,在一些需要用户给予评分的推荐系统中,则要代入用户评分。

实例讲解:

本文将基于之前的博文《使用C#+Jumony开发网络爬虫并对数据做相关分析》

使用爬虫爬取的 伯乐在线 网站的用户信息实现。

 

数据实体:

  1. 用户,使用网站主页URL地址作为唯一标识

    例如:用户:唐小娟,主页URL地址为:http://www.jobbole.com/members/ tangxiaojuan/

  1. 该用户的关注人,目前爬虫只取主页有的关注用户,其他更多关注用户没有获取。

实现过程:

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

注:本文参考项亮编著的《推荐系统实践》一书。

标签: C# 算法
最后更新:2021年4月1日

博主

全栈工程师,侧重项目技术解决方案规划和开发

打赏 点赞
< 上一篇
下一篇 >

文章评论

取消回复

分类
  • .NET (65)
  • docker (3)
  • linux (12)
  • python (20)
  • web (14)
  • 小程序 (4)
  • 数据库 (2)
  • 未分类 (4)
  • 杂七杂八 (10)
标签聚合
nginx js winform centos C# DevExpress python linux
最新 热点 随机
最新 热点 随机
.NET开发手册标准参考 招募兼职前端开发 Centos安装dotnet6环境 VS上切换分支,vs编译运行出现bug,A fatal error was encountered彻底解决方案 用C#封装一个线程安全的缓存器,达到目标定时定量更新入库 C#通过特性的方式去校验指定数据是否为空
使用C#+Jumony开发网络爬虫并对数据做相关分析 python守护进程--supervisor 使用教程 ubuntu18.04使用GPU部署学习后的中文OCR识别完整教程 dynamic的操作 WinForm使用简单的方法实现完美遮罩的效果 主程序ui线程异常处理方案和只允许同时运行一个进程的方法

COPYRIGHT © 2021 陈程的技术博客. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS