65.9K
CodeProject 正在变化。 阅读更多。
Home

推荐引擎

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (12投票s)

2018年3月5日

MIT

11分钟阅读

viewsIcon

17609

downloadIcon

490

本文介绍了一个用 C# 编写的推荐引擎或协同过滤系统。

引言

这是我参加“志同道合”机器学习和人工智能挑战赛的参赛作品。本文介绍了一个用 C# 编写的推荐引擎或协同过滤系统。

背景

本文是我的“志同道合”竞赛参赛作品。

推荐引擎是一种软件,可以根据用户之前表达的喜欢或不喜欢来预测用户可能喜欢或不喜欢的内容。它可以作为搜索的替代方案或与搜索结合使用,因为它有助于用户发现他们可能没有接触过的产品或内容。推荐引擎是亚马逊、Facebook、电影以及互联网上许多内容网站的重要组成部分。

这里给出的挑战是获取一组数据,并根据这些数据为用户提供推荐。我熟悉推荐引擎或协同过滤的结果,因为我使用亚马逊,但从未真正编写或使用过一个。我觉得这将是一个有趣的挑战,并给我一个学习更多机器学习知识的机会。我不确定在三周的周末工作中能否完成它,但这个主题很有趣,也是一个挑战。

我开始研究如何设计和构建推荐引擎。我阅读了许多关于解决这个问题的不同方法的帖子、博客和文章,因为这是一个许多人似乎都感兴趣的常见问题。这些文章中使用的方法和技术都有几个共同点,并进行了两组计算。

首先,计算系统中两个评分者之间的相似度。根据评分者之间的相似度,计算用户喜欢任何特定项目的概率。推荐引擎基于这样的想法:如果 A 类似于 B,C 类似于 B,那么 A 也必须类似于 C。但是,仅仅因为我喜欢你喜欢的一篇文章或几篇文章,并不一定意味着我喜欢你喜欢的所有其他文章。因此,这些数据点之间的相关性很弱。

我看到了几种方法,但我最终选择了这种方法。

他很好地概述了这些方程式的来源和方式。请随意阅读他的文章以更好地理解这种方法。这种方法还为我们提供了一个介于 -1.0 和 1.0 之间的相似度评级,其中 -1 表示完全不相似,1 表示完全相似。没有足够数据来计算相似度的用户,其相似度为 0,结果将被丢弃。我运行了一些数字来测试他的数学并验证他的公式,结果似乎符合我的预期,所以我决定将它们作为本文的基础。

相似度方程

S(U1, U2) = (L1 交集 L2) + (D1 交集 D2) – (L1 交集 D2) – (L2 交集 D1) / (L1 并集 L2 并集 D1 并集 D2)

S(U1, U2) = 用户一和用户二之间的相似度 – 一个介于 -1 到 1 之间的值 – 零概率意味着没有足够的数据进行计算

  • L1 交集 L2 – 用户一喜欢的文章中用户二也喜欢的数量
  • D1 交集 D2 – 用户一不喜欢的文章中用户二也不喜欢的数量
  • L1 交集 D2 – 用户一喜欢的文章中用户二不喜欢的数量
  • L2 交集 D1 – 用户二喜欢的文章中用户一不喜欢的数量
  • L1 并集 L2 并集 D1 并集 D2 – 用户一喜欢的文章数量加上用户二喜欢的文章数量加上用户一不喜欢的文章数量加上用户二不喜欢的文章数量

相似度方程 - 使用标签定义系统内的相似度

我还尝试使用与文章相关的标签来计算系统中所有用户的喜欢和不喜欢。我已经将代码分离出来,以便很容易插入不同的公式来计算用户之间的相似度。

使用当前加载的用户的喜欢和不喜欢,将每个标签在这些文章中出现的次数进行整理,以创建下面插入到上述相似度公式中的数字。下面,我概述了哪些值被插入到这些公式中。我举了一个如何计算各种值的例子。

作为一个简单的计算示例

所以,如果一个

用户1      
  喜欢 - 文章一  
      标签 = A,B,C
    文章二  
      标签-A,B,E,F
用户2      
  喜欢    
    文章三  
      标签=A,B,C
    文章四  
      标签=A,G,H
用户1 A-2, B – 2,C – 1,E- 1,F -1 总计 = 7
用户2 =A-2, B-1, C-1, G-1,H-1 总计 = 6
      总计=13

U1 交集 U2 标签 = A,B,C = A-4, B-3, C-2 = 9

  • S(U1, U2) = (L1 交集 L2) + (D1 交集 D2) – (L1 交集 D2) – (L2 交集 D1) / (L1 并集 L2 并集 D1 并集 D2)
  • (L1 交集 L2) – 这首先生成与用户1和用户2都喜欢的每篇文章相关的所有标签的交集。最终数字是用户1和用户2这些标签的出现次数。
  • (D1 交集 D2) – 这首先生成与用户1和用户2都不喜欢的每篇文章相关的所有标签的交集。最终数字是用户1和用户2这些标签的出现次数。
  • (L1 交集 D2) – 这首先生成与用户1喜欢而用户2不喜欢的每篇文章相关的所有标签的交集。最终数字是用户1和用户2这些标签的出现次数。
  • (L2 交集 D1) – 这首先生成与用户1不喜欢而用户2喜欢的每篇文章相关的所有标签的交集。最终数字是用户1和用户2这些标签的出现次数。
  • (L1 并集 L2 并集 D1 并集 D2) – 这首先生成与用户1喜欢、用户1不喜欢、用户2喜欢和用户2不喜欢的每篇文章相关的所有标签的并集。最终数字是用户1喜欢和不喜欢以及用户2喜欢和不喜欢这些标签的出现次数。

概率方程

这生成一个介于 -1.0 到 1.0 之间的值,其中 -1.0 表示用户或评分者有 100% 的概率不喜欢被评分者,1.0 表示用户或评分者有 100% 的概率喜欢该文章。

P(U,A) = (Zl – Zd) / (Ml + Md)

  • P(U,A) – 用户或评分者喜欢特定被评分者或文章的概率
  • Zl – 喜欢该文章的用户或评分者的相似度指数总和
  • Zd – 不喜欢该文章的用户相似度指数总和
  • Ml – 喜欢该文章或被评分者的用户或评分者总数
  • Md – 不喜欢该文章或被评分者的用户或评分者总数

Using the Code

在这种情况下,我们获得了一组用户、文章、标签和用户行为,其中包括查看、下载、点赞或点踩。

由于示例数据包含 3000 个用户和 3000 篇文章,并且每个用户必须对系统中的每个用户进行相似度计算,然后计算用户喜欢系统中每篇文章的概率,所以每次运行需要 18,000,000 次计算。因此,每次都需要一段时间。我确实并行运行概率计算以加快速度,这大约将这些计算的时间缩短了一半。

基类

RaterBase – 系统中任何评分者的基类。我用 User 类进行重载。

Likes – 评分者喜欢的被评分者列表
Dislikes – 评分者不喜欢的被评分者列表
Similarities – 系统中所有用户列表,值介于 -1.0 到 1.0 之间
Ratees – 被评分者字典,包含评分者喜欢被评分者的概率,值介于 -1.0 到 1.0 之间

RateeBase – 任何被评分者的基类。我用 Article 类进行重载。

Likes – 喜欢被评分者的评分者列表
Dislikes – 喜欢被评分者的评分者列表

Similarity – 作为列表保存在 RaterBase::Similarities 类中。

评分者

UserAction – 系统中的用户或评分者行为

评分者
被评分者
Action – 用户可以执行 UpVoteDownVoteViewDownload

RecommenderBase

Raters – 所有用户或评分者
Ratees – 所有被评分者或文章
Ratings – 所有 UserActions 列表
Likes – 所有喜欢的用户行为
Dislikes – 所有不喜欢的用户行为
AddUserActionsToLikes – 可以将一类 UserActions 添加到数据中 – 允许我轻松地将 ViewsDownloads 添加到测试数据集
InitializeStatistics – 用于构建统计数据以供以后使用的内务处理方法
GenerateSimilaritiesValuesForUsers – 从“喜欢”和“不喜欢”中提取值,生成介于 -1.0 和 1.0 之间的相似度值
GenerateRatingsProbabilitiesForUsers – 生成每个用户喜欢文章的概率,值介于 -1.0 和 1.0 之间

派生类

ArticleRecommender : RecommenderBase

Tags – 所有标签的列表
Downloads – 所有 DownloadsUserAction 列表
Views – 所有 ViewsUserAction 列表
LoadData(string filename,string actionlike,string actionDislike)

User: RaterBase

Views – 用户查看的 Ratees
Downloads – 用户下载的 Ratees
GenerateSimilaritiesByTags – 这使用标签生成用户相似度。它使用他们的喜欢和不喜欢,并计算每个标签在该列表中出现的次数来衡量哪些标签是重要的。

Tag

ID
名称

Article 继承自 RateeBase

Tags – 与文章关联的标签
Views – 查看此被评分者的评分者
Downloads – 下载此被评分者的评分者

基本思想是将数据加载到用户的 LikesDislikes 中,然后调用 GenerateSimilaritiesValuesForUsers(),然后调用 GenerateRatingsProbabilitiesForUsers()。要使用标签关联加载的数据,请使用 GenerateSimilaritiesByTags(),然后使用 GenerateRatingsProbabilitiesForUsers()AddUserActionsToLikes()RemoveUserActionsToLikes() 允许从数据集中添加和删除 UserActions。有关所有涉及的代码的完整列表,请参阅 Program.cs 文件,因为它会对数据进行处理。

// example usage…
 
ArticleRecommender recommendationEngine = new ArticleRecommender("Userbehaviour.txt");
 
// optional to add more UserAction data to test
recommendationEngine.AddUserActionsToLikes("Download");
recommendationEngine.GenerateSimilarityValuesForUsers();
recommendationEngine.GenerateRatingsProbabilitiesForUsers();
 
// usage to use tags for the similarities correlations
recommendationEngine.GenerateSimilaritiesByTags ();
recommendationEngine.GenerateRatingsProbabilitiesForUsers();

关注点

有趣的是,将浏览和下载添加到总体的喜欢中,并没有实质性地改变用户之间的总体相关性或相似度。这表明,被浏览和下载的文章与用户花时间喜欢或不喜欢的文章是不同的。

我得到的最高值大约是 0.25,非常低。在我看来,我计算相似度的方式可能存在问题,尽管我查看了代码并查看了给定的内容,计算出来的值似乎是准确的(即,进入计算的值似乎与文章一致。我正在使用文档。我运行了许多测试来验证公式和代码,它们似乎是正确的)。可能是网站上没有很多用户做了很多操作,所以像我这样尝试在用户之间进行关联不是正确的方法。网站上可能还有很多内容,都被均匀地阅读、点赞、点踩和下载。结果是网站上没有明确的最受欢迎内容,因为大多数文章的统计数据大致相同。这将是一个有趣的探索方向。

我认为一个更可能富有成效的方法是像我一样使用与文章相关的标签。通过对视图进行加权,我为数据上的每种切割类型都得到了从 1 到 -1 的值。只有 30 个标签,这使得关联更容易,这可能会使结果偏高。但是,根据我的初步结果,这似乎是迄今为止获得的最佳结果。

我发现这很有趣,也很有趣。如果我真的想做更多机器学习方面的事情,我想我需要更好地掌握 Python 和/或学习 R。C# 对于做我所做的一些事情来说有点笨重。

我的代码没有像我希望的那样经过充分测试或验证。概念都在那里,但考虑到时间框架,实际代码可能存在错误。我肯定可以做一些事情来加快速度。

过去几年,我一直在冬天滑雪,但膝盖软骨撕裂的手术让我过去几周卧床不起。我利用日程中的额外时间完成了这个挑战。感谢 CodeProject 举办这个挑战,让我不再想念滑雪!

我希望有人觉得它有用和有教育意义。

历史

  • 2018 年 3 月 4 日 – 初稿
  • 2018 年 3 月 9 日 - 将 UserBehavior.txt 文件添加到项目中,以便编译并使用该文件
© . All rights reserved.