Apache mahout 源码阅读笔记-DataModel之UserBaseRecommender
@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的更多相关文章
- Apache mahout 源码阅读笔记--DataModel之FileDataModel
要做推荐,用户行为数据是基础. 用户行为数据有哪些字段呢? mahout的DataModel支持,用户ID,ItemID是必须的,偏好值(用户对当前Item的评分),时间戳 这四个字段 {@code ...
- Apache mahout 源码阅读笔记--协同过滤, PearsonCorrelationSimilarity
协同过滤源码路径: ~/project/javaproject/mahout-0.9/core/src $tree main/java/org/apache/mahout/cf/taste/ -L 2 ...
- Apache Storm源码阅读笔记
欢迎转载,转载请注明出处. 楔子 自从建了Spark交流的QQ群之后,热情加入的同学不少,大家不仅对Spark很热衷对于Storm也是充满好奇.大家都提到一个问题就是有关storm内部实现机理的资料比 ...
- Mina源码阅读笔记(四)—Mina的连接IoConnector2
接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- CI框架源码阅读笔记2 一切的入口 index.php
上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...
- 源码阅读笔记 - 1 MSVC2015中的std::sort
大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...
随机推荐
- Apache Rewrite 拟静态
mod_rewrite是Apache的一个非常强大的功能,它可以实现伪静态页面.一些防盗链就是通过该方法做到的. 00x1 启动rewrite引擎 00x2 如何启用apache rewrite? 0 ...
- 虚拟机和Docker的异同
[摘要]各种虚拟机技术开启了云计算时代:而Docker,作为下一代虚拟化技术,正在改变我们开发.测试.部署应用的方式.那虚拟机与Docker究竟有何不同呢? 首先,大家需要明确一点,Docker容器不 ...
- Ubuntu Python 安装numpy SciPy、MatPlotLib环境
安装 sudo apt-get install python-scipysudo apt-get install python-numpysudo apt-get install python-mat ...
- imx6 uboot splash image
跟踪uboot代码,了解imx6 splash image的生成过程. 涉及文件: ./cpu/arm_cortexa8/start.S ./board/freescale/mx6q_sabresd/ ...
- 【BZOJ】1679: [Usaco2005 Jan]Moo Volume 牛的呼声(数学)
http://www.lydsy.com/JudgeOnline/problem.php?id=1679 水题没啥好说的..自己用笔画画就懂了 将点排序,然后每一次的点到后边点的声音距离和==(n-i ...
- RabbitMQ组成及原理介绍-3
rabbitmq作为成熟的企业消息中间件,实现了应用程序间接口调用的解耦,提高系统的吞吐量. 1.RabbitMQ组成 是由 LShift 提供的一个 Advanced Message Queuing ...
- 深入分析jquery解析json数据
我们先以解析上例中的comments对象的JSON数据为例,然后再小结jQuery中解析JSON数据的方法. JSON数据如下,是一个嵌套JSON: {"comments":[{& ...
- 传递任意数量的实参*parameter&使用任意数量的关键字实参**parameter
1.*形参名(*parameter) 有时候我们不知道知道函数需要接受多少个实参,所以我们可以在形参名前加一个*,是让python创建一个名为parameter的空元组,并将收到的所有值都封装到这个元 ...
- JavaScript 二、eval 和 with 函数
/* * ========================================================= * * JavaScript 词法欺骗 * * 1.欺骗词法作用域,会导致 ...
- 将Oracle数据库转换为SQL Server
(转发)近期为公司的一个项目数据库进行了转换,将Oracle的Db转换为SqlServer(2000或2005均可),一开始在网上找了一些资料,发现有个工具叫SwisSql的,尝试了一下,没成功,继续 ...