先来看一下使用流程:
1)拿到DataModel
2)定义相似度计算模型 PearsonCorrelationSimilarity
3)定义用户邻域计算模型 NearestNUserNeighborhood
4)定义推荐模型 GenericUserBasedRecommender
5)进行推荐
  @Test
public void testHowMany() throws Exception {
DataModel dataModel = getDataModel(
new long[] {1, 2, 3, 4, 5},
new Double[][] {
{0.1, 0.2},
{0.2, 0.3, 0.3, 0.6},
{0.4, 0.4, 0.5, 0.9},
{0.1, 0.4, 0.5, 0.8, 0.9, 1.0},
{0.2, 0.3, 0.6, 0.7, 0.1, 0.2},
});
//用于计算最相似的用户,领域用户
UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);
UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, dataModel); Recommender recommender = new GenericUserBasedRecommender(dataModel, neighborhood, similarity);
List<RecommendedItem> fewRecommended = recommender.recommend(1, 2);
List<RecommendedItem> moreRecommended = recommender.recommend(1, 4);
for (int i = 0; i < fewRecommended.size(); i++) {
assertEquals(fewRecommended.get(i).getItemID(), moreRecommended.get(i).getItemID());
}
recommender.refresh(null);
for (int i = 0; i < fewRecommended.size(); i++) {
assertEquals(fewRecommended.get(i).getItemID(), moreRecommended.get(i).getItemID());
}
}

相似度计算,参考上篇的PearsonCorrelationSimilarity。

NearestNUserNeighborhood ,获取最近的N个用户,怎么实现的呢?
~/mahout-core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java
  @Override
public List<RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) throws TasteException {
Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); log.debug("Recommending items for user ID '{}'", userID); //根据similarity模型进行计算,计算最相似的N个用户
long[] theNeighborhood = neighborhood.getUserNeighborhood(userID); if (theNeighborhood.length == 0) {
return Collections.emptyList();
}
//获取其他领域用户进行评分而且当前用户所没有进行评分的Item列表,作为推荐的基本池子
FastIDSet allItemIDs = getAllOtherItems(theNeighborhood, userID); //获取池子里面,当前用户偏好最高的TopN进行推荐
TopItems.Estimator<Long> estimator = new Estimator(userID, theNeighborhood); List<RecommendedItem> topItems = TopItems
.getTopItems(howMany, allItemIDs.iterator(), rescorer, estimator); log.debug("Recommendations are: {}", topItems);
return topItems;
}
Estimator的实现,是这样的:
  private final class Estimator implements TopItems.Estimator<Long> {

    private final long theUserID;
private final long[] theNeighborhood; Estimator(long theUserID, long[] theNeighborhood) {
this.theUserID = theUserID;
this.theNeighborhood = theNeighborhood;
} @Override
public double estimate(Long itemID) throws TasteException {
return doEstimatePreference(theUserID, theNeighborhood, itemID);
}
}
}
 
  protected float doEstimatePreference(long theUserID, long[] theNeighborhood, long itemID) throws TasteException {
//把相似用户对该Item的偏好累加起来,再做平均值,当做当前用户对改Item的偏好
if (theNeighborhood.length == 0) {
return Float.NaN;
}
DataModel dataModel = getDataModel();
double preference = 0.0;
double totalSimilarity = 0.0;
int count = 0;
for (long userID : theNeighborhood) {
if (userID != theUserID) {
// See GenericItemBasedRecommender.doEstimatePreference() too
Float pref = dataModel.getPreferenceValue(userID, itemID);
if (pref != null) {
double theSimilarity = similarity.userSimilarity(theUserID, userID);
if (!Double.isNaN(theSimilarity)) {
preference += theSimilarity * pref;
totalSimilarity += theSimilarity;
count++;
}
}
}
}
// Throw out the estimate if it was based on no data points, of course, but also if based on
// just one. This is a bit of a band-aid on the 'stock' item-based algorithm for the moment.
// The reason is that in this case the estimate is, simply, the user's rating for one item
// that happened to have a defined similarity. The similarity score doesn't matter, and that
// seems like a bad situation.
if (count <= 1) {
return Float.NaN;
}
float estimate = (float) (preference / totalSimilarity);
if (capper != null) {
estimate = capper.capEstimate(estimate);
}
return estimate;
}
总结:
1)计算最相似的N个用户
2)从最相似的N个用户中,获取自己没有评分过的Item
3)预计自己对每个Item的偏好
4)取偏好最高的N个Item进行推荐

Apache mahout 源码阅读笔记-DataModel之UserBaseRecommender的更多相关文章

  1. Apache mahout 源码阅读笔记--DataModel之FileDataModel

    要做推荐,用户行为数据是基础. 用户行为数据有哪些字段呢? mahout的DataModel支持,用户ID,ItemID是必须的,偏好值(用户对当前Item的评分),时间戳 这四个字段 {@code ...

  2. Apache mahout 源码阅读笔记--协同过滤, PearsonCorrelationSimilarity

    协同过滤源码路径: ~/project/javaproject/mahout-0.9/core/src $tree main/java/org/apache/mahout/cf/taste/ -L 2 ...

  3. Apache Storm源码阅读笔记

    欢迎转载,转载请注明出处. 楔子 自从建了Spark交流的QQ群之后,热情加入的同学不少,大家不仅对Spark很热衷对于Storm也是充满好奇.大家都提到一个问题就是有关storm内部实现机理的资料比 ...

  4. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  5. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  6. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  7. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  8. CI框架源码阅读笔记2 一切的入口 index.php

    上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...

  9. 源码阅读笔记 - 1 MSVC2015中的std::sort

    大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...

随机推荐

  1. poj2559单调栈

    题意:给出连续的矩形的高....求最大面积 #include<iostream> #include<stack> #include<stdio.h> using n ...

  2. 一款基于jQuery的热点新闻Tab选项卡插件

    今天要分享的jQuery焦点图插件非常适合展示热点新闻,之前我们分享过好多基于jQuery的焦点图插件,效果都还很不错.它可以在图片上方展示文字标题,并且焦点图的切换按钮时tab风格的,图片切换也十分 ...

  3. 软件配置管理中的SVN

    一.简单介绍 1.什么是软件配置管理 软件配置管理是指通过运行版本号控制.变更控制的规程.以及使用合适的配置管理软件.来保证全部配置项的完整性和可跟踪性. 配置管理是对工作成果的一种有效保护. 2.为 ...

  4. [driver]linux内核动态加载模块

    问题: 1. 把编译好的模块放到板子/lib/modules对应文件夹下,并且执行了depmod -a, 比如pl2303.ko, 那么下一次插入pl2303的串口线,是否可以识别,也就是自动加载pl ...

  5. Linux网络编程wait()和waitpid()的讲解

    本文讲的是关于wait和waitpid两者的区别与联系.为避免僵尸进程的产生,无论我们什么时候创建子进程时,主进程都需要等待子进程返回,以便对子进程进行清理.为此,我们在服务器程序中添加SIGCHLD ...

  6. sama5d3 开入测试

    root@sama5d3-linux:~ echo 20 > /sys/class/gpio/export root@sama5d3-linux:~ echo 16 > /sys/clas ...

  7. ipipe-3.10

    git://git.xenomai.org/ipipe-gch.git for-ipipe-3.10

  8. Easyui 编辑表格行删除

    1.问题描述 easyui 编辑表格新增一条数据后,删除最后一行删除不了,原因是没有提交数据acceptChanges. 源码中deleteRow方法,根据坐标获取行html,方法为opts.find ...

  9. 模拟HttpContext单元测试

    众所周知 ASP.NET MVC 的一个显著优势即可以很方便的实现单元测试,但在我们测试过程中经常要用到HttpContext,而默认情况下单元测试框架是不提供HttpContext的模拟的,本文通过 ...

  10. java----Servlet的生命周期

    Servlet生命周期分为三个阶段: 1,初始化阶段  调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...