一、概念

协同过滤算法主要分为基于用户的协同过滤算法和基于项目的协同过滤算法。

 
基于用户的协同过滤算法和基于项目的协同过滤算法
1.1、以用户为基础(User-based)的协同过滤

用相似统计的方法得到具有相似爱好或者兴趣的相邻用户,所以称之为以用户为基础(User-based)的协同过滤或基于邻居的协同过滤(Neighbor-based Collaborative Filtering)。

具体步骤为:

1.收集用户信息
收集可以代表用户兴趣的信息。一般的网站系统使用评分的方式或是给予评价,这种方式被称为“主动评分”。另外一种是“被动评分”,是根据用户的行为模式由系统代替用户完成评价,不需要用户直接打分或输入评价数据。电子商务网站在被动评分的数据获取上有其优势,用户购买的商品记录是相当有用的数据。

2.最近邻搜索(Nearest neighbor search, NNS)
以用户为基础(User-based)的协同过滤的出发点是与用户兴趣爱好相同的另一组用户,就是计算两个用户的相似度。例如:查找n个和A有相似兴趣用户,把他们对M的评分作为A对M的评分预测。一般会根据数据的不同选择不同的算法,较多使用的相似度算法有Pearson Correlation Coefficient、Cosine-based Similarity、Adjusted Cosine Similarity。

3.产生推荐结果
有了最近邻集合,就可以对目标用户的兴趣进行预测,产生推荐结果。依据推荐目的的不同进行不同形式的推荐,较常见的推荐结果有Top-N 推荐和关系推荐。Top-N 推荐是针对个体用户产生,对每个人产生不一样的结果,例如:通过对A用户的最近邻用户进行统计,选择出现频率高且在A用户的评分项目中不存在的,作为推荐结果。关系推荐是对最近邻用户的记录进行关系规则(association rules)挖掘。

1.2、以项目为基础(Item-based)的协同过滤

以用户为基础的协同推荐算法随着用户数量的增多,计算的时间就会变长,所以在2001年Sarwar提出了基于项目的协同过滤推荐算法(Item-based Collaborative Filtering Algorithms)。以项目为基础的协同过滤方法有一个基本的假设“能够引起用户兴趣的项目,必定与其之前评分高的项目相似”,通过计算项目之间的相似性来代替用户之间的相似性。

具体步骤为:

1.收集用户信息
同以用户为基础(User-based)的协同过滤。

2.针对项目的最近邻搜索
先计算已评价项目和待预测项目的相似度,并以相似度作为权重,加权各已评价项目的分数,得到待预测项目的预测值。例如:要对项目 A 和项目 B 进行相似性计算,要先找出同时对 A 和 B 打过分的组合,对这些组合进行相似度计算,常用的算法同以用户为基础(User-based)的协同过滤。

3.产生推荐结果
以项目为基础的协同过滤不用考虑用户间的差别,所以精度比较差。但是却不需要用户的历史数据,或是进行用户识别。对于项目来讲,它们之间的相似性要稳定很多,因此可以离线完成工作量最大的相似性计算步骤,从而降低了在线计算量,提高推荐效率,尤其是在用户多于项目的情形下尤为显著。

二、隐式反馈 VS 显性反馈

2.1、概念

隐性反馈行为:不能明确反映用户喜好的行为。

显性反馈行为:用户明确表示对物品喜好的行为。

显性反馈行为包括用户明确表示对物品喜好的行为,隐性反馈行为指的是那些不能明确反应用户喜好的行为。在许多的现实生活中的很多场景中,我们常常只能接触到隐性的反馈,例如页面游览,点击,购买,喜欢,分享等等。
基于矩阵分解的协同过滤的标准方法,一般将用户商品矩阵中的元素作为用户对商品的显性偏好。在 MLlib 中所用到的处理这种数据的方法来源于文献: Collaborative Filtering for Implicit Feedback Datasets 。 本质上,这个方法将数据作为二元偏好值和偏好强度的一个结合,而不是对评分矩阵直接进行建模。因此,评价就不是与用户对商品的显性评分,而是与所观察到的用户偏好强度关联起来。然后,这个模型将尝试找到隐语义因子来预估一个用户对一个商品的偏好。

2.2、显性反馈数据和隐形反馈数据的比较
 
显性反馈数据和隐形反馈数据的比较
2.3、各代表网站中显性反馈数据和隐性反馈数据的例子
 
各代表网站中显性反馈数据和隐性反馈数据的例子

三、代码实现

下面代码读取spark的示例文件,文件中每一行包括一个用户id、商品id和评分。我们使用默认的ALS.train() 方法来构建推荐模型并评估模型的均方差。

3.1、导入需要的包:
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.mllib.recommendation.ALS;
import org.apache.spark.mllib.recommendation.MatrixFactorizationModel;
import org.apache.spark.mllib.recommendation.Rating;
3.2、读取数据:

首先,读取文本文件,把数据转化成rating类型,即[Int, Int, Double]的RDD;

/**
* 1、获取spark
*/
SparkConf conf = new SparkConf().setAppName("CollaborativeModel").setMaster("local");
JavaSparkContext sc = new JavaSparkContext(conf);
/**
* 2、读取文本文件,把数据转化成rating类型,即[Int, Int, Double]的RDD
*/
JavaRDD<String> source = sc.textFile("data/mllib/collaborative.data");
JavaRDD<Rating> ratings = source.map(line->{
String[] parts = line.split(",");
return new Rating(Integer.parseInt(parts[0]),
Integer.parseInt(parts[1]),
Double.parseDouble(parts[2]));
});
ratings.foreach(x->{
System.out.println(x);
});
/**
*控制台输出结果:
*Rating中的第一个int是user编号,第二个int是item编号,最后的double是user对item的评分。
----------------
Rating(1,1,5.0)
Rating(3,2,5.0)
Rating(1,2,1.0)
Rating(3,3,1.0)
Rating(1,3,5.0)
Rating(3,4,5.0)
Rating(1,4,1.0)
Rating(4,1,1.0)
Rating(2,1,5.0)
Rating(4,2,5.0)
Rating(2,2,1.0)
Rating(4,3,1.0)
Rating(2,3,5.0)
Rating(4,4,5.0)
Rating(2,4,1.0)
Rating(3,1,1.0)
----------------
**/
3.3、构建模型

划分训练集和测试集,比例分别是0.8和0.2。

JavaRDD<Rating>[] splits =  ratings.randomSplit(new double[] {0.8,0.2});
JavaRDD<Rating> training = splits[0];
JavaRDD<Rating> test = splits[1];

指定参数值,然后使用ALS训练数据建立推荐模型:

int rank = 10;
int numIterations = 10;
/**
* 可以调整这些参数,不断优化结果,使均方差变小。比如:iterations越多,lambda较小,均方差会较小,推荐结果较优
*/
MatrixFactorizationModel model = ALS.train(training.rdd(),rank,numIterations,0.01);

在 MLlib 中的实现有如下的参数:

numBlocks 是用于并行化计算的分块个数 (设置为-1,为自动配置)。

rank 是模型中隐语义因子的个数。

iterations 是迭代的次数。

lambda 是ALS的正则化参数。

implicitPrefs 决定了是用显性反馈ALS的版本还是用适用隐性反馈数据集的版本。

alpha 是一个针对于隐性反馈 ALS 版本的参数,这个参数决定了偏好行为强度的基准。

可以调整这些参数,不断优化结果,使均方差变小。比如:iterations越多,lambda较小,均方差会较小,推荐结果较优。上面的例子中调用了 ALS.train(ratings, rank, numIterations, 0.01) ,我们还可以设置其他参数,调用方式如下:

MatrixFactorizationModel model2 = new  ALS().setRank(10)
.setIterations(2000)
.setLambda(0.01)
.setImplicitPrefs(true)
.setUserBlocks(10)
.setProductBlocks(10)
.run(training);
3.4、 利用模型进行预测

从 test训练集中获得只包含用户和商品的数据集 :

JavaRDD<Tuple2<Object, Object>>  testUsersProducts = test.map(line->{
return new Tuple2<>(line.user(),line.product());
});

使用训练好的推荐模型对用户商品进行预测评分,得到预测评分的数据集:

JavaPairRDD<Tuple2<Integer, Integer>, Double>  predictions =JavaPairRDD.fromJavaRDD(
model.predict(testUsersProducts.rdd()).toJavaRDD().map(r->
new Tuple2<>(new Tuple2<>(r.user(),r.product()),r.rating())));

将真实评分数据集与预测评分数据集进行合并。这里,Join操作类似于SQL的inner join操作,返回结果是前面和后面集合中配对成功的,过滤掉关联不上的。

JavaPairRDD<Tuple2<Integer, Integer>, Double>  predictions = JavaPairRDD.fromJavaRDD(
model.predict(testUsersProducts.rdd()).toJavaRDD().map(r->
new Tuple2<>(new Tuple2<>(r.user(),r.product()),r.rating())));
System.out.println(predictions);
predictions.foreach(x->{
System.out.println(x);
});
/**
*控制台输出结果:
*Rating中的第一个int是user编号,第二个int是item编号,最后的double是user对item的评分。
----------------------------
((4,2),0.010526887751696495)
((1,1),3.6826782499237716)
((1,2),0.7464017268228036)
((3,2),0.010526887751696495)
----------------------------
**/

我们把结果输出,对比一下真实结果与预测结果:

JavaPairRDD<Tuple2<Integer, Integer>, Tuple2<Double, Double>> ratesAndPreds = JavaPairRDD.fromJavaRDD(test.map(x->new Tuple2<>(
new Tuple2<>(x.user(),x.product()),x.rating()))).join(predictions); System.out.println("------------------------------------------");
ratesAndPreds.foreach(x->{
System.out.println(x);
});
/**
*控制台输出结果:
*比如,第二条结果记录((4,2),(5.0,0.010526887751696495))中,(4,2)分别表示4号用户和2号商品,而5.0是实际的估计分值,
*0.010526887751696495是经过推荐的预测分值。
-----------------------------------
((1,1),(5.0,3.6826782499237716))
((4,2),(5.0,0.010526887751696495))
((1,2),(1.0,0.7464017268228036))
((3,2),(5.0,0.010526887751696495))
-----------------------------------
**/

比如,第二条结果记录((4,2),(5.0,0.010526887751696495))中,(4,2)分别表示4号用户和2号商品,而5.0是实际的估计分值,0.010526887751696495是经过推荐的预测分值。
然后计算均方差,这里的r1就是真实结果,r2就是预测结果:

double MSE = ratesAndPreds.values().mapToDouble(x->{
double err = x._1() - x._2();
return err * err;
}).mean();
System.out.println("Mean Squared Error = "+MSE);
/**
*控制台输出结果:
-----------------------------------
Mean Squared Error = 2.8413113799948704
-----------------------------------
**/

我们可以看到打分的均方差值为1.09左右。由于本例的数据量很少,预测的结果和实际相比有一定的差距。上面的例子只是对测试集进行了评分,我们还可以进一步的通过调用model.recommendProducts给特定的用户推荐商品以及model.recommendUsers来给特定商品推荐潜在用户。

spark机器学习从0到1协同过滤算法 (九)的更多相关文章

  1. Spark机器学习之协同过滤算法

    Spark机器学习之协同过滤算法 一).协同过滤 1.1 概念 协同过滤是一种借助"集体计算"的途径.它利用大量已有的用户偏好来估计用户对其未接触过的物品的喜好程度.其内在思想是相 ...

  2. Spark机器学习(11):协同过滤算法

    协同过滤(Collaborative Filtering,CF)算法是一种常用的推荐算法,它的思想就是找出相似的用户或产品,向用户推荐相似的物品,或者把物品推荐给相似的用户.怎样评价用户对商品的偏好? ...

  3. 【机器学习笔记一】协同过滤算法 - ALS

    参考资料 [1]<Spark MLlib 机器学习实践> [2]http://blog.csdn.net/u011239443/article/details/51752904 [3]线性 ...

  4. Spark 基于物品的协同过滤算法实现

    J由于 Spark MLlib 中协同过滤算法只提供了基于模型的协同过滤算法,在网上也没有找到有很好的实现,所以尝试自己实现基于物品的协同过滤算法(使用余弦相似度距离) 算法介绍 基于物品的协同过滤算 ...

  5. Spark MLlib协同过滤算法

    算法说明 协同过滤(Collaborative Filtering,简称CF,WIKI上的定义是:简单来说是利用某个兴趣相投.拥有共同经验之群体的喜好来推荐感兴趣的资讯给使用者,个人透过合作的机制给予 ...

  6. 机器学习 | 简介推荐场景中的协同过滤算法,以及SVD的使用

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第29篇文章,我们来聊聊SVD在上古时期的推荐场景当中的应用. 推荐的背后逻辑 有没有思考过一个问题,当我们在淘宝或者是 ...

  7. Collaborative Filtering(协同过滤)算法详解

    基本思想 基于用户的协同过滤算法是通过用户的历史行为数据发现用户对商品或内容的喜欢(如商品购买,收藏,内容评论或分享),并对这些喜好进行度量和打分.根据不同用户对相同商品或内容的态度和偏好程度计算用户 ...

  8. 吴裕雄--天生自然HADOOP操作实验学习笔记:协同过滤算法

    实验目的 初步认识推荐系统 学会用mapreduce实现复杂的算法 学会系统过滤算法的基本步骤 实验原理 前面我们说过了qq的好友推荐,其实推荐算法是所有机器学习算法中最重要.最基础.最复杂的算法,一 ...

  9. win7下使用Taste实现协同过滤算法

    如果要实现Taste算法,必备的条件是: 1) JDK,使用1.6版本.需要说明一下,因为要基于Eclipse构建,所以在设置path的值之前要先定义JAVA_HOME变量. 2) Maven,使用2 ...

随机推荐

  1. Xshell下载和连接Linux

    Xshell下载和连接Linux 第一步.Xshell的下载 方法1:从官网下载个人使用时免费的,商业使用是要收费的. http://www.xshellcn.com/ 方法二2:百度云下载Xshel ...

  2. Java代码生成器加入postgresql数据库、HikariCP连接池、swagger2支持!

    目录 前言 PostgreSql VS MySql HikariCP VS Druid Swagger2 自定义参数配置一览 结语 前言   最近几天又抽时间给代码生成器增加了几个新功能(预计今晚发布 ...

  3. 如何在没有安装 Python 的机器上运行 Python 程序

    cmd 命令 1. pip install pyinstaller 2. pyinstaller <path to your prog.py> 3. 应用程序在prog.py同路径下的 d ...

  4. Python爬虫之记录一次下载验证码的尝试

      好久没有写过爬虫的文章了,今天在尝试着做验证码相关的研究时,遇到了验证码的收集问题.   一般,验证码的加载都有着比较复杂的算法和加密在里边,但是笔者今天碰到的验证码却比较幸运,有迹可循.在此,给 ...

  5. 对 ThreadLocal 的了解(一)

    Threadlocal ThreadLocal 在我个人理解范围内,主要作用是在同一个线程里面,去共享某个数据给这个线程在不同的阶段去使用. 本次使用范围 在集成 pageOffice 在线 word ...

  6. dhcpd.conf(5) - Linux man page

    http://linux.die.net/man/5/dhcpd.conf Name dhcpd.conf - dhcpd configuration file Description   The d ...

  7. Android环境配置----在Ubuntu上安装JDK

    jdk download address: jdk-6u22-linux-i586.bin http://www.oracle.com/technetwor ... ownloads/index.ht ...

  8. Codeforces Round #623 (Div. 2, based on VK Cup 2019-2020 - Elimination Round, Engine) C. Restoring

    C. Restoring Permutation time limit per test1 second memory limit per test256 megabytes inputstandar ...

  9. 面试被问为什么使用Spring Boot?答案好像没那么简单

    面试官:项目中有使用Spring Boot吗? 小小白:用过. 面试官:说一下为什么要使用Spring Boot? 小小白:在使用Spring框架进行开发的过程中,需要配置很多Spring框架包的依赖 ...

  10. xml出现Exception in thread "main" java.lang.NullPointerException

    运行代码出现Exception in thread "main" java.lang.NullPointerException 可以看下这个链接:https://ask.csdn. ...