文档章节

探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤(二)

东方神剑
 东方神剑
发布于 2014/11/13 11:52
字数 3739
阅读 128
收藏 8
点赞 0
评论 0

基于 Apache Mahout 实现高效的协同过滤推荐

Apache Mahout 是 Apache Software Foundation (ASF) 旗下的一个开源项目,提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序,并且,在 Mahout 的最近版本中还加入了对 Apache Hadoop 的支持,使这些算法可以更高效的运行在云计算环境中。

关于 Apache Mahout 的安装和配置请参考《基于 Apache Mahout 构建社会化推荐引擎》,它是笔者 09 年发表的一篇关于基于 Mahout 实现推荐引擎的 developerWorks 文章,其中详细介绍了 Mahout 的安装步骤,并给出一个简单的电影推荐引擎的例子。

Apache Mahout 中提供的一个协同过滤算法的高效实现,它是一个基于 Java 实现的可扩展的,高效的推荐引擎。图 4 给出了 Apache Mahout 中协同过滤推荐实现的组件图,下面我们逐步深入介绍各个部分。

图 4.组件图

图 4 组件图

数据表示:Data Model

Preference

基于协同过滤的推荐引擎的输入是用户的历史偏好信息,在 Mahout 里它被建模为 Preference(接口),一个 Preference 就是一个简单的三元组 < 用户 ID, 物品 ID, 用户偏好 >,它的实现类是 GenericPreference,可以通过以下语句创建一个 GenericPreference。

GenericPreference preference = new GenericPreference(123, 456, 3.0f);

这其中, 123 是用户 ID,long 型;456 是物品 ID,long 型;3.0f 是用户偏好,float 型。从这个例子我们可以看出,单单一个 GenericPreference 的数据就占用 20 bytes,所以你会发现如果只简单实用数组 Array 加载用户偏好数据,必然占用大量的内存,Mahout 在这方面做了一些优化,它创建了 PreferenceArray(接口)保存一组用户偏好数据,为了优化性能,Mahout 给出了两个实现类,GenericUserPreferenceArray 和 GenericItemPreferenceArray,分别按照用户和物品本身对用户偏好进行组装,这样就可以压缩用户 ID 或者物品 ID 的空间。下面清单 1 的代码以 GenericUserPreferenceArray 为例,展示了如何创建和使用一个 PreferenceArray。

清单 1. 创建和使用 PreferenceArray
 PreferenceArray userPref = new GenericUserPreferenceArray(2); //size = 2 

 userPref.setUserID(0, 1L); 

 userPref.setItemID(0, 101L);  //<1L, 101L, 2.0f> 
 userPref.setValue(0, 2.0f); 
 userPref.setItemID(1, 102L);  //<1L, 102L, 4.0f> 
 userPref.setValue(1, 4.0f); 

 Preference pref = userPref.get(1);   //<1L, 102L, 4.0f>

为了提高性能 Mahout 还构建了自己的 HashMap 和 Set:FastByIDMap 和 FastIDSet,有兴趣的朋友可以参考 Mahout 官方说明。

DataModel

Mahout 的推荐引擎实际接受的输入是 DataModel,它是对用户偏好数据的压缩表示,通过创建内存版 DataModel 的语句我们可以看出:

DataModel model = new GenericDataModel(FastByIDMap<PreferenceArray> map);

他保存在一个按照用户 ID 或者物品 ID 进行散列的 PreferenceArray,而 PreferenceArray 中对应保存着这个用户 ID 或者物品 ID 的所有用户偏好信息。

DataModel 是用户喜好信息的抽象接口,它的具体实现支持从任意类型的数据源抽取用户喜好信息,具体实现包括内存版的 GenericDataModel,支持文件读取的 FileDataModel 和支持数据库读取的 JDBCDataModel,下面我们看看如何创建各种 DataModel。

清单 2. 创建各种 DataModel
 //In-memory DataModel - GenericDataModel 
 FastByIDMap<PreferenceArray> preferences = new FastByIDMap<PreferenceArray>(); 

 PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10);  
 prefsForUser1.setUserID(0, 1L); 
 prefsForUser1.setItemID(0, 101L); 
 prefsForUser1.setValue(0, 3.0f);  
 prefsForUser1.setItemID(1, 102L); 
 prefsForUser1.setValue(1, 4.5f); 
… (8 more) 
 preferences.put(1L, prefsForUser1);   //use userID as the key 
… (more users) 

 DataModel model = new GenericDataModel(preferences); 

 //File-based DataModel - FileDataModel 
 DataModel dataModel = new FileDataModel(new File("preferences.csv"); 

 //Database-based DataModel - MySQLJDBCDataModel 
 MysqlDataSource dataSource = new MysqlDataSource(); 
 dataSource.setServerName("my_user"); 
 dataSource.setUser("my_password"); 
 dataSource.setPassword("my_database_host"); 
 JDBCDataModel dataModel = new MySQLJDBCDataModel(dataSource, "my_prefs_table", 
 "my_user_column", "my_item_column", "my_pref_value_column");

支持文件读取的 FileDataModel,Mahout 没有对文件的格式做过多的要求,只要文件的内容满足以下格式:

  • 每一行包括用户 ID, 物品 ID, 用户偏好

  • 逗号隔开或者 Tab 隔开

  • *.zip 和 *.gz 文件会自动解压缩(Mahout 建议在数据量过大时采用压缩的数据存储)

支持数据库读取的 JDBCDataModel,Mahout 提供一个默认的 MySQL 的支持,它对用户偏好数据的存放有以下简单的要求:

  • 用户 ID 列需要是 BIGINT 而且非空

  • 物品 ID 列需要是 BIGINT 而且非空

  • 用户偏好列需要是 FLOAT

建议在用户 ID 和物品 ID 上建索引。

实现推荐:Recommender

介绍完数据表示模型,下面介绍 Mahout 提供的协同过滤的推荐策略,这里我们选择其中最经典的三种,User CF, Item CF 和 Slope One。

User CF

前面已经详细介绍了 User CF 的原理,这里我们着重看怎么基于 Mahout 实现 User CF 的推荐策略,我们还是从一个例子入手:

清单 3. 基于 Mahout 实现 User CF
 DataModel model = new FileDataModel(new File("preferences.dat")); 
 UserSimilarity similarity = new PearsonCorrelationSimilarity(model); 
 UserNeighborhood neighborhood = new NearestNUserNeighborhood(100, similarity, model); 
 Recommender recommender = new GenericUserBasedRecommender(model, 
 neighborhood, similarity);
  1. 从文件建立 DataModel,我们采用前面介绍的 FileDataModel,这里假设用户的喜好信息存放在 preferences.dat 文件中。

  2. 基于用户偏好数据计算用户的相似度,清单中采用的是 PearsonCorrelationSimilarity,前面章节曾详细介绍了各种计算相似度的方法,Mahout 中提供了基本的相似度的计算,它们都 UserSimilarity 这个接口,实现用户相似度的计算,包括下面这些常用的:

  • PearsonCorrelationSimilarity:基于皮尔逊相关系数计算相似度

  • EuclideanDistanceSimilarity:基于欧几里德距离计算相似度

  • TanimotoCoefficientSimilarity:基于 Tanimoto 系数计算相似度

  • UncerteredCosineSimilarity:计算 Cosine 相似度

ItemSimilarity 也是类似的:

  1. 根据建立的相似度计算方法,找到邻居用户。这里找邻居用户的方法根据前面我们介绍的,也包括两种:“固定数量的邻居”和“相似度门槛邻居”计算方法,Mahout 提供对应的实现:

    • NearestNUserNeighborhood:对每个用户取固定数量 N 的最近邻居

    • ThresholdUserNeighborhood:对每个用户基于一定的限制,取落在相似度门限内的所有用户为邻居。

  2. 基于 DataModel,UserNeighborhood 和 UserSimilarity 构建 GenericUserBasedRecommender,实现 User CF 推荐策略。

Item CF

了解了 User CF,Mahout Item CF 的实现与 User CF 类似,是基于 ItemSimilarity,下面我们看实现的代码例子,它比 User CF 更简单,因为 Item CF 中并不需要引入邻居的概念:

清单 4. 基于 Mahout 实现 Item CF
 DataModel model = new FileDataModel(new File("preferences.dat")); 
 ItemSimilarity similarity = new PearsonCorrelationSimilarity(model); 
 Recommender recommender = new GenericItemBasedRecommender(model, similarity);

Slope One

如前面介绍的,User CF 和 Item CF 是最常用最容易理解的两种 CF 的推荐策略,但在大数据量时,它们的计算量会很大,从而导致推荐效率较差。因此 Mahout 还提供了一种更加轻量级的 CF 推荐策略:Slope One。

Slope One 是有 Daniel Lemire 和 Anna Maclachlan 在 2005 年提出的一种对基于评分的协同过滤推荐引擎的改进方法,下面简单介绍一下它的基本思想。

图 5 给出了例子,假设系统对于物品 A,物品 B 和物品 C 的平均评分分别是 3,4 和 4。基于 Slope One 的方法会得到以下规律:

  • 用户对物品 B 的评分 = 用户对物品 A 的评分 + 1

  • 用户对物品 B 的评分 = 用户对物品 C 的评分

基于以上的规律,我们可以对用户 A 和用户 B 的打分进行预测:

  • 对用户 A,他给物品 A 打分 4,那么我们可以推测他对物品 B 的评分是 5,对物品 C 的打分也是 5。

  • 对用户 B,他给物品 A 打分 2,给物品 C 打分 4,根据第一条规律,我们可以推断他对物品 B 的评分是 3;而根据第二条规律,推断出评分是 4。当出现冲突时,我们可以对各种规则得到的推断进行就平均,所以给出的推断是 3.5。

这就是 Slope One 推荐的基本原理,它将用户的评分之间的关系看作简单的线性关系:

Y = mX + b;

当 m = 1 时就是 Slope One,也就是我们刚刚展示的例子。

图 5.Slope One 推荐策略示例

图 5 Slope One 推荐策略示例

Slope One 的核心优势是在大规模的数据上,它依然能保证良好的计算速度和推荐效果。Mahout 提供了 Slope One 推荐方法的基本实现,实现代码很简单,参考清单 5.

清单 5. 基于 Mahout 实现 Slope One
 //In-Memory Recommender 
 DiffStorage diffStorage = new MemoryDiffStorage(model, Weighting.UNWEIGHTED, false, 
 Long.MAX_VALUE)); 
 Recommender recommender = new SlopeOneRecommender(model, Weighting.UNWEIGHTED, 
 Weighting.UNWEIGHTED, diffStorage);  

 //Database-based Recommender 
 AbstractJDBCDataModel model = new MySQLJDBCDataModel(); 
 DiffStorage diffStorage = new MySQLJDBCDiffStorage(model); 
 Recommender recommender = new SlopeOneRecommender(model, Weighting.WEIGHTED, 
 Weighting.WEIGHTED, diffStorage);

1. 根据 Data Model 创建数据之间线性关系的模型 DiffStorage。

2. 基于 Data Model 和 DiffStorage 创建 SlopeOneRecommender,实现 Slope One 推荐策略。


回页首

总结

Web2.0 的一个核心思想就是“集体智慧”,基于协同过滤的推荐策略的基本思想就是基于大众行为,为每个用户提供个性化的推荐,从而使用户能更快速更准确的发现所需要的信息。从应用角度分析,现今比较成功的推荐引擎,比如 Amazon,豆瓣,当当等都采用了协同过滤的方式,它不需要对物品或者用户进行严格的建模,而且不要求物品的描述是机器可理解的,是中领域无关的推荐方法,同时这个方法计算出来的推荐是开放的,可以共用他人的经验,很好的支持用户发现潜在的兴趣偏好。基于协同过滤的推荐策略也有不同的分支,它们有不同的实用场景和推荐效果,用户可以根据自己应用的实际情况选择合适的方法,异或组合不同的方法得到更好的推荐效果。

除此之外,本文还介绍了如何基于 Apache Mahout 高效实现协同过滤推荐算法,Apache Mahout 关注海量数据上的机器学习经典算法的高效实现,其中对基于协同过滤的推荐方法也提供了很好的支持,基于 Mahout 你可以轻松的体验高效推荐的神奇。

作为深入推荐引擎相关算法的第一篇文章,本文深入介绍了协同过滤算法,并举例介绍了如何基于 Apache Mahout 高效实现协同过滤推荐算法,Apache Mahout 作为海量数据上的机器学习经典算法的高效实现,其中对基于协同过滤的推荐方法也提供了很好的支持,基于 Mahout 你可以轻松的体验高效推荐的神奇。但我们也发现了在海量数据上高效的运行协同过滤算法以及其他推荐策略这样高复杂的算法还是有很大的挑战的。在面对这个问题的过程中,大家提出了很多减少计算量的方法,而聚类无疑是其中最优的选择。所以本系列的下一篇文章将详细介绍各类聚类算法,它们的原理,优缺点和实用场景,并给出基于 Apache Mahout 的聚类算法的高效实现,并分析在推荐引擎的实现中,如何通过引入聚类来解决大数据量造成的海量计算,从而提供高效的推荐。

最后,感谢大家对本系列的关注和支持。

参考资料

学习

本文转载自:http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy2/index.html

共有 人打赏支持
东方神剑

东方神剑

粉丝 64
博文 126
码字总数 93166
作品 0
朝阳
程序员
探索推荐引擎内部的秘密,第 1 部分: 推荐引擎初探

信息发现 如今已经进入了一个数据爆炸的时代,随着 Web 2.0 的发展, Web 已经变成数据分享的平台,那么,如何让人们在海量的数据中想要找到他们需要的信息将变得越来越难。 在这样的情形下,...

东方神剑
2014/11/13
0
0
Apache Mahout中推荐算法Slope one源码分析

关于推荐引擎 如今的互联网中,无论是电子商务还是社交网络,对数据挖掘的需求都越来越大了,而推荐引擎正是数据挖掘完美体现;通过分析用户历史行为,将他可能喜欢内容推送给他,能产生相当...

Breath_L
2012/02/11
0
6
探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤

集体智慧和协同过滤 什么是集体智慧 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web 应用中利用集体智慧构建更加有趣的应用或者得到更好的用...

Endeavour
2015/08/12
0
0
[IBM DW] 购物网站商品推荐引擎初探

随着 Web 技术的发展,使得内容的创建和分享变得越来越容易。每天都有大量的图片、博客、视频发布到网上。信息的极度爆炸使得人们找到他们需要的信息将变得越来越 难。传统的搜索技术是一个相...

红薯
2011/03/20
1K
2
基于协同过滤,NMF和Baseline的推荐算法

杂谈 老早就想整理一篇推荐算法的入门博文,今天抽空写一下。本文以电影推荐系统为例,简单地介绍基于协同过滤,PMF概率矩阵分解,NMF非负矩阵分解和Baseline的推荐系统算法。NMF的实现具体可...

初雪之音
2015/10/07
3.7K
3
推荐机制 协同过滤和基于内容推荐的区别

参考ibm文章 https://www.ibm.com/developerworks/cn/web/1103zhaoctrecommstudy1/index.html 该系列分为三部分 第 2 部分: 深入推荐引擎相关算法 - 协同过滤 第 3 部分: 深入推荐引擎相关算...

liaomin416100569
04/13
0
0
探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤(一)

集体智慧和协同过滤 什么是集体智慧 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web 应用中利用集体智慧构建更加有趣的应用或者得到更好的用...

东方神剑
2014/11/13
0
0
深入推荐引擎相关算法 - 协同过滤

在现今的推荐技术和算法中,最被大家广泛认可和采用的就是基于协同过滤的推荐方法。它以其方法模型简单,数据依赖性低,数据方便采集 , 推荐效果较优等多个优点成为大众眼里的推荐算法“No....

IBMdW
2011/03/25
0
0
机器学习相关——协同过滤

在现今的推荐技术和算法中,最被大家广泛认可和采用的就是基于协同过滤的推荐方法。本文将带你深入了解协同过滤的秘密。下面直接进入正题 1 什么是协同过滤 协同过滤是利用集体智慧的一个典型...

~大器晚成~
2012/02/01
0
0
机器学习(Machine Learning)&深入学习(Deep Learning)资料

《Brief History of Machine Learning》 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机、神经网络、决策树、SVM、Adaboost到随机森林、Deep Learning. 《Deep Learning in Ne...

JDquant
2017/08/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

设计神器 - 摹客设计系统上线了 | 晒出你的设计规范,赢iPad Pro!

在国内,设计规范也许还是个不太常用的概念,但是如果你正好有参与互联网公司的产品设计,你应该早就已经体会到设计规范的重要性了。UI设计师总是要花费大量的时间和精力向开发描述一大堆设计...

mo311
12分钟前
0
0
Thymeleaf 使用过程中的一些记录

Thymeleaf格式化时间: th:value="${#dates.format(gw.regDT,'yyyy-MM-ddHH:mm:ss')}" Thymeleaf select反选: <select id="status" name="status" th:field="${gw.status}" th:value="${gw.......

惊尘大人
15分钟前
0
0
istio源码分析之pilot-discovery模块分析

本文分析的istio代码版本为0.8.0,commit为0cd8d67,commit时间为2018年6月18日。 本文为Service Mesh深度学习系列之一: Service Mesh深度学习系列part1—istio源码分析之pilot-agent模块分...

xiaomin0322
20分钟前
0
0
数据库基本操作:增删改查及联表操作

所用软件:SQL Server Management Studio 首先第一步,建立一个表。在这里命名为T1。并在里面填入几条数据。如图: T1 一.查询 查询所有:select * from T1; 按条件查询:select * from T1 ...

小_橙_子
24分钟前
0
0
Crontab作业时间设置

今天,遇到这么一个题目,周一到周五的9:00-16:59之间,每隔两分钟将某个命令运行一次。给的答案是: */2 9-16 * * 1-5 /usr/sbin/somecommand dosomething 乍一看,这个答案不对,应...

大别阿郎
29分钟前
0
0
ES17-JAVA API文档管理

1.保存文档 可以通过json工具把java对象转换成json字符串进行保存,也可以通过内置的帮助类直接构建json格式 /** * 获取客户端 * * @return */public static TransportClie...

贾峰uk
30分钟前
0
0
Python代码规范和命名规范

前言 Python 学习之旅,先来看看 Python 的代码规范,让自己先有个意识,而且在往后的学习中慢慢养成习惯 一、简明概述 1、编码 如无特殊情况, 文件一律使用 UTF-8 编码 如无特殊情况, 文件头...

blackfoxya
33分钟前
0
0
联动滑动之一:NestScrollChild和NestedScrollingParent

NestScrollChild和NestedScrollingParent 吐槽一下开源中国竟然标题字数有限制 由于项目中使用了CoordinateLayout来解决联动以及实现炫酷的UI效果,那么必须就要研究一波源码了,毕竟知其然知...

JerryLin123
50分钟前
1
0
cloudera spark2.2 读写hbase

cloudera spark2.2 读写hbase 例子 host = 'bigdata-03,bigdata-05,bigdata-04'conf = { "hbase.zookeeper.quorum": host, "hbase.mapreduce.inputtable": "student1"}k......

osenlin
54分钟前
0
0
数据库规范化

转载自 一个小时学会MySQL数据库 地址:http://www.cnblogs.com/best/p/6517755.html 截取其中 1.4 部分 用于自己学习使用 感谢作者:张果 1.4、数据库规范化 经过一系列的步骤,我们现在终于...

十万猛虎下画山
55分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部