mahout算法源码分析之Collaborative Filtering with ALS-WR (四)评价和推荐
Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit。
首先来总结一下 mahout算法源码分析之Collaborative Filtering with ALS-WR (三),这个写了三篇,基本都是写QR分解,然后矩阵进过处理得到U或者M的过程,但是还是没有讲出个所以然来。mahout官网上说其是根据这篇文献得来的Large-scale Parallel Collaborative Filtering for the Netflix Prize,本来我是想翻译这篇来着,就是为了想弄清楚这个所谓的QR分解算法,但是感觉好像和mahout中的实现不同。(这篇在csdn上面已经有人翻译了,但是真的只是翻译而已,并没有进行讲解,结果还是自己来看),其中主要的是下面的matlab部分代码:
这里是使用给定的U来更新M,mahout中第一个是用M--1来更新U-0,其实都是一样的。看上面的图,其中的vector其实就是Vi,而matrix其实就是Ai(对应于前篇blog中相应的变量),所以matrix\vector 其实就相当于Ai\Vi = Ai‘*Vi(Ai的逆矩阵和Vi相乘)这样就可以得到M。额,或许这里的mahout代码就是求Ai的逆矩阵?恩,很有可能这样的话,应该是对到了。只是这里求Ai的逆矩阵代码太复杂了。这个有时间还是要慢慢研究下的。
今天本来就不打算纠结这个问题了,没想到又看一遍居然好像有点领悟了(之前一直以为逆矩阵和转置矩阵一样的,导致以为mahout代码和matlab代码不符,哎,还是矩阵没学好。。。)
本篇正文:评价这个算法,在mahout中其实就是使用了一个参数而已,rmse,均方根误差。运行这一步其实就是先使用前面一步获得的U和M来对每个用户应经评价的movies进行重新评价,即评价预测。然后把真是评价分数和预测评价分数的误差写入文件。最后读出误差列,把其求平均得到最后误差结果。在mahout中评价使用的job文件是:org.apache.mahout.cf.taste.hadoop.als.FactorizationEvaluator。打开这个文件,可以看到在run方法中有一个parepareJob的函数,同时这个函数的Mapper是PredictRatingsMapper。打开这个PredictRatingsMapper可以看到它有setup和map函数,setup函数主要是把路径U和M中的数据load到一个变量里面,map是主要操作,源码如下:
protected void map(LongWritable key, Text value, Context ctx) throws IOException, InterruptedException {
String[] tokens = TasteHadoopUtils.splitPrefTokens(value.toString());
int userID = Integer.parseInt(tokens[0]);
int itemID = Integer.parseInt(tokens[1]);
double rating = Double.parseDouble(tokens[2]);
if (U.containsKey(userID) && M.containsKey(itemID)) {
double estimate = U.get(userID).dot(M.get(itemID));
double err = rating - estimate;
ctx.write(new DoubleWritable(err), NullWritable.get());
}
}
额 ,好吧首先说下这个输入数据,格式为:userid,itemid,rating。然后map遍历每条记录,首先把当前记录中的userID、ItemID和rating提取出来,然后从U和M中分别取出userid和itemid对应的行或列向量,取出来后,把这两个向量做点乘即可得到最后的预测评价分数。然后使用是真实的评价分数减去预测的评价分数即可得到误差,进行输出即可。在这个job运行完成后,随机代码就调用了computeRmse函数来对输出文件进行分析,求出最后的rmse:
protected double computeRmse(Path errors) {
RunningAverage average = new FullRunningAverage();
for (Pair<DoubleWritable,NullWritable> entry :
new SequenceFileDirIterable<DoubleWritable, NullWritable>(errors, PathType.LIST, PathFilters.logsCRCFilter(),
getConf())) {
DoubleWritable error = entry.getFirst();
average.addDatum(error.get() * error.get());
}
return Math.sqrt(average.getAverage());
}
然后是推荐,推荐使用的源码是在:org.apache.mahout.cf.taste.hadoop.als.RecommenderJob。这里run方法中的prepareJob中使用的mapper是PredictionMapper。这个mapper中同样含有setup和map函数,其中的setup函数还是获取U和M,不过还额外获取了一个MaxRating变量。map中的处理比较多,先贴源码吧:
protected void map(IntWritable userIDWritable, VectorWritable ratingsWritable, Context ctx)
throws IOException, InterruptedException { Vector ratings = ratingsWritable.get();
final int userID = userIDWritable.get();
final OpenIntHashSet alreadyRatedItems = new OpenIntHashSet(ratings.getNumNondefaultElements());
final TopK<RecommendedItem> topKItems = new TopK<RecommendedItem>(recommendationsPerUser, BY_PREFERENCE_VALUE); Iterator<Vector.Element> ratingsIterator = ratings.iterateNonZero();
while (ratingsIterator.hasNext()) {
alreadyRatedItems.add(ratingsIterator.next().index());
} M.forEachPair(new IntObjectProcedure<Vector>() {
@Override
public boolean apply(int itemID, Vector itemFeatures) {
if (!alreadyRatedItems.contains(itemID)) {
double predictedRating = U.get(userID).dot(itemFeatures);
topKItems.offer(new GenericRecommendedItem(itemID, (float) predictedRating));
}
return true;
}
}); List<RecommendedItem> recommendedItems = Lists.newArrayListWithExpectedSize(recommendationsPerUser);
for (RecommendedItem topItem : topKItems.retrieve()) {
recommendedItems.add(new GenericRecommendedItem(topItem.getItemID(), Math.min(topItem.getValue(), maxRating)));
} if (!topKItems.isEmpty()) {
ctx.write(userIDWritable, new RecommendedItemsWritable(recommendedItems));
}
}
先说下这个输入格式吧:<key,vlaue> --> <userid,[itemid:rating,itemid,rating,...],针对当前的输入,首先获取用户userid和这个用户所有评价过的item(放在alreadyRatedItems) 。然后遍历所有M中的item如果这个item不存在于alreadyRatedItems那么就对这个item进行评分预测,预测使用的还是在U中和M中取出分别对应userid和itemid的行、列向量进行点乘即可得到预测分数,然后把这个预测的分数加入到topKItems中,看下这个变量的定义:
final TopK<RecommendedItem> topKItems = new TopK<RecommendedItem>(recommendationsPerUser, BY_PREFERENCE_VALUE);
这里的BY_PREFERENCE_VALUE实现了comparator接口,所以加入到这个变量中的会按照一定的顺序来排列,即按照value(即预测的分数)从大到小来排列。然后就是输出了。这样这个系列就全部分析完毕了。
额,还有一点,关于matlab代码部分的算法其实是和mahout源码中的一致的,具体下篇分析。
分享,成长,快乐
转载请注明blog地址:http://blog.csdn.net/fansy1990
mahout算法源码分析之Collaborative Filtering with ALS-WR (四)评价和推荐的更多相关文章
- mahout算法源码分析之Collaborative Filtering with ALS-WR拓展篇
Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit. 额,好吧,心头的一块石头总算是放下了.关于Collaborative Filtering with AL ...
- mahout算法源码分析之Collaborative Filtering with ALS-WR 并行思路
Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit. mahout算法源码分析之Collaborative Filtering with ALS-WR 这个算 ...
- mahout算法源码分析之Itembased Collaborative Filtering(二)RowSimilarityJob
Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit. 本篇开始之前先来验证前篇blog的分析结果,编写下面的测试文件来进行对上篇三个job的输出进行读取: p ...
- mahout算法源码分析之Itembased Collaborative Filtering(四)共生矩阵乘法
Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit. 经过了SimilarityJob的计算共生矩阵后,就可以开始下面一个过程了,这个过程主要是共生矩阵的乘法 ...
- mahout算法源码分析之Itembased Collaborative Filtering(三)RowSimilarityJob验证
Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit. 本篇分析上篇的分析是否正确,主要是编写上篇输出文件的读取以及添加log信息打印相关变量. 首先,编写下面 ...
- diff.js 列表对比算法 源码分析
diff.js列表对比算法 源码分析 npm上的代码可以查看 (https://www.npmjs.com/package/list-diff2) 源码如下: /** * * @param {Arra ...
- Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四)
Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四) 题记:本来计划的SolrCloud的Recovery策略的文章是3篇的,但是没想到Recovery的内容蛮多的,前面 ...
- OpenCV人脸识别Eigen算法源码分析
1 理论基础 学习Eigen人脸识别算法需要了解一下它用到的几个理论基础,现总结如下: 1.1 协方差矩阵 首先需要了解一下公式: 共公式可以看出:均值描述的是样本集合的平均值,而标准差描述的则是样本 ...
- 朴素贝叶斯算法源码分析及代码实战【python sklearn/spark ML】
一.简介 贝叶斯定理是关于随机事件A和事件B的条件概率的一个定理.通常在事件A发生的前提下事件B发生的概率,与在事件B发生的前提下事件A发生的概率是不一致的.然而,这两者之间有确定的关系,贝叶斯定理就 ...
随机推荐
- php类的属性
属性声明是由关键字 public,protected 或者 private 开头,后面跟一个普通的变量声明来组成.属性的变量可以设置初始化的默认值,默认值必须是常量. class Car { //定义 ...
- hadoop1 和haddop2 mapperreducer的wordcount详解
转 mapreduce中wordcount详细介绍(包括hadoop1和hadoop2版本) 发表于1年前(2014-04-24 10:08) 阅读(1458) | 评论(0) 1人收藏此文章, ...
- linux服务器监控流量sh脚本
服务器可能经常遇到服务器出带宽跑满,不知如何查询被哪个进程占用的情况,有一款开源的英文软件iftop功能比较强大可以查询相关信息,可能刚接触linux系统的朋友不太会使用,在此写了一个功能比较简单无需 ...
- Servlet+Tomcat制作出第一个运行在Tomcat上的Java应用程序
转载自:http://www.linuxidc.com/Linux/2011-08/41685.htm [日期:2011-08-27] 来源:csdn 作者:Cloudyxuq 1.IDE工 ...
- 三菱plc输出指示灯不亮怎么办(转载)
三菱plc输出指示灯不亮怎么办?三菱plc输出指示灯故障 时间:2015-10-21 07:31:12编辑:电工栏目:三菱plc 导读:三菱plc输出指示灯不亮故障的原因,三菱plc在使用中出现输出指 ...
- 打开网页自动弹出qq客户端
新建js后调用即可,打开网站自动弹出qq对话框,若qq为关闭状态则启动qq,之后弹出对话框. document.write("<iframe src='tencent://messag ...
- QLGame 2D Engine编写环境搭建
QLGame 2D Engine编写 (win7环境搭建) 广州麒麟网络工作室,计划制作一款2d game engine,基于opengl(es)平台,暂时支持android,以后考虑支持linux, ...
- PYTHON之DEF
def sayHello(): print('Hello World!') while True: s = input('Enter something : ') if s == 'quit': br ...
- php 文件上传 以及保存在本地的乱码问题处理
要知道两点: ①浏览器传到PHP程序中是UTF-8编码 ②PHP程序保存上传的文件,要转换成GBK编码才保存在本地中,否则如果直接使用浏览器传过来的文件名保存在本地,会出现文件名乱码. <?ph ...
- 李洪强iOS开发Swift篇—08_函数(2)
李洪强iOS开发Swift篇—08_函数(2) 一.函数类型 函数类型也是数据类型的一种,它由形参类型和返回值类型组成,格式是 (形参类型列表) -> 返回值类型 1 func sum(num1 ...