先来看一下使用流程:
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. CodeForces 558D

     Guess Your Way Out! II Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & ...

  2. 本地vagrant配置虚拟域名的坑

    修改 /usr/local/php56/etc/php.d/Zend.ini   文件 将developer.zl的路径加上去 修改nginx 的vhost里面的xx.com.conf 和上一级目录的 ...

  3. java 解压.gz文件

    1.//建立gzip压缩文件输入流 2.建立gzip解压工作流 fileInputStream = new FileInputStream(filePath + fileName); //解凍する G ...

  4. Unix网络编程中的五种I/O模型_转

    转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描 ...

  5. 关于HTTP的长连接和短连接

    1. HTTP协议与TCP/IP协议的关系 HTTP的长连接和短连接本质上是TCP长连接和短连接.HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议. IP协议主要解决网络路由和寻址 ...

  6. SQL合并数据

    --CREATE TABLE TMaterial (PMaterial INT,FName NVARCHAR(32))--INSERT INTO TMaterial--SELECT 1,'A' UNI ...

  7. 对map进行排序

    public class TreeMapTest {    public static void main(String[] args) {        Map<String, String& ...

  8. 关于json动态拼接响应数据

    在EasyUI http://www.jeasyui.com/demo/main/get_users.php 响应数据如下格式: { "total": "11" ...

  9. ios 从URL中截取所包含的参数,并且以字典的形式返回和参数字典转URL

    //字典转链接(参数) - (NSString *)keyValueStringWithDict:(NSDictionary *)dict { if (dict == nil) { return ni ...

  10. AWS系列-EC2默认限制说明

    Amazon EC2 提供您可以使用的不同资源,例如实例和卷. 在您创建 AWS 账户时,AWS 会针对每个区域中的这些资源设置限制.此页面列出您在 亚太区域 (东京) 中的 EC2 服务限制. 1. ...