Apache mahout 源码阅读笔记--协同过滤, PearsonCorrelationSimilarity
协同过滤源码路径:
~/project/javaproject/mahout-0.9/core/src $tree main/java/org/apache/mahout/cf/taste/ -L 2
main/java/org/apache/mahout/cf/taste/
├── common
│ ├── NoSuchItemException.java
│ ├── NoSuchUserException.java
│ ├── Refreshable.java
│ ├── TasteException.java
│ └── Weighting.java
├── eval
│ ├── DataModelBuilder.java
│ ├── IRStatistics.java
│ ├── RecommenderBuilder.java
│ ├── RecommenderEvaluator.java
│ ├── RecommenderIRStatsEvaluator.java
│ └── RelevantItemsDataSplitter.java
├── hadoop
│ ├── EntityEntityWritable.java
│ ├── EntityPrefWritable.java
│ ├── MutableRecommendedItem.java
│ ├── RecommendedItemsWritable.java
│ ├── TasteHadoopUtils.java
│ ├── ToEntityPrefsMapper.java
│ ├── ToItemPrefsMapper.java
│ ├── TopItemsQueue.java
│ ├── als
│ ├── item
│ ├── preparation
│ └── similarity
├── impl
│ ├── common
│ ├── eval
│ ├── model
│ ├── neighborhood
│ ├── recommender
│ └── similarity
├── model
│ ├── DataModel.java
│ ├── IDMigrator.java
│ ├── JDBCDataModel.java
│ ├── Preference.java
│ ├── PreferenceArray.java
│ └── UpdatableIDMigrator.java
├── neighborhood
│ └── UserNeighborhood.java
├── recommender
│ ├── CandidateItemsStrategy.java
│ ├── IDRescorer.java
│ ├── ItemBasedRecommender.java
│ ├── MostSimilarItemsCandidateItemsStrategy.java
│ ├── RecommendedItem.java
│ ├── Recommender.java
│ ├── Rescorer.java
│ └── UserBasedRecommender.java
└── similarity
├── ItemSimilarity.java
├── PreferenceInferrer.java
├── UserSimilarity.java
└── precompute
similarity 相似度的interface定义
recommender 推荐算法的interface定义
model 数据model类型的interface定义
impl 目录 则是以上interface定义的实现
PearsonCorrelationSimilarity的实现在
~/mahout-core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/PearsonCorrelationSimilarity.java
/**
* @throws IllegalArgumentException if {@link DataModel} does not have preference values
*/
public PearsonCorrelationSimilarity(DataModel dataModel, Weighting weighting) throws TasteException {
//这里CenterData传的时true
/* pearson其实做的事情就是先把两个向量都减去他们的平均值,然后再计算cosine值。
* 在 AbstractSimilarity里的实现代码如下:
* double result;
if (centerData) {
double meanX = sumX / count;
double meanY = sumY / count;
// double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n * meanX * meanY;
double centeredSumXY = sumXY - meanY * sumX;
// double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX * meanX;
double centeredSumX2 = sumX2 - meanX * sumX;
// double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY * meanY;
double centeredSumY2 = sumY2 - meanY * sumY;
result = computeResult(count, centeredSumXY, centeredSumX2, centeredSumY2, sumXYdiff2);
} else {
result = computeResult(count, sumXY, sumX2, sumY2, sumXYdiff2);
}
*/
super(dataModel, weighting, true);
Preconditions.checkArgument(dataModel.hasPreferenceValues(), "DataModel doesn't have preference values");
} @Override
double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) {
if (n == 0) {
return Double.NaN;
}
// Note that sum of X and sum of Y don't appear here since they are assumed to be 0;
// the data is assumed to be centered.
double denominator = Math.sqrt(sumX2) * Math.sqrt(sumY2);
if (denominator == 0.0) {
// One or both parties has -all- the same ratings;
// can't really say much similarity under this measure
return Double.NaN;
}
return sumXY / denominator;
}
就是数学公式的实现:
具体的累加,在interface里面已经做了,:
@Override
public double userSimilarity(long userID1, long userID2) throws TasteException {
DataModel dataModel = getDataModel();
//获取用户偏好
PreferenceArray xPrefs = dataModel.getPreferencesFromUser(userID1);
PreferenceArray yPrefs = dataModel.getPreferencesFromUser(userID2);
int xLength = xPrefs.length();
int yLength = yPrefs.length(); if (xLength == 0 || yLength == 0) {
return Double.NaN;
} long xIndex = xPrefs.getItemID(0);
long yIndex = yPrefs.getItemID(0);
int xPrefIndex = 0;
int yPrefIndex = 0; double sumX = 0.0;
double sumX2 = 0.0;
double sumY = 0.0;
double sumY2 = 0.0;
double sumXY = 0.0;
double sumXYdiff2 = 0.0;
int count = 0; boolean hasInferrer = inferrer != null; while (true) {
int compare = xIndex < yIndex ? -1 : xIndex > yIndex ? 1 : 0;
if (hasInferrer || compare == 0) {
double x;
double y;
if (xIndex == yIndex) {
// Both users expressed a preference for the item
x = xPrefs.getValue(xPrefIndex);
y = yPrefs.getValue(yPrefIndex);
} else {
//如果不存在对应的分数,则进行推断...
// Only one user expressed a preference, but infer the other one's preference and tally
// as if the other user expressed that preference
if (compare < 0) {
// X has a value; infer Y's
x = xPrefs.getValue(xPrefIndex);
y = inferrer.inferPreference(userID2, xIndex);
} else {
// compare > 0
// Y has a value; infer X's
x = inferrer.inferPreference(userID1, yIndex);
y = yPrefs.getValue(yPrefIndex);
}
}
sumXY += x * y;
sumX += x;
sumX2 += x * x;
sumY += y;
sumY2 += y * y;
double diff = x - y;
sumXYdiff2 += diff * diff;
count++;
}
if (compare <= 0) {
if (++xPrefIndex >= xLength) {
if (hasInferrer) {
// Must count other Ys; pretend next X is far away
if (yIndex == Long.MAX_VALUE) {
// ... but stop if both are done!
break;
}
xIndex = Long.MAX_VALUE;
} else {
break;
}
} else {
xIndex = xPrefs.getItemID(xPrefIndex);
}
}
if (compare >= 0) {
if (++yPrefIndex >= yLength) {
if (hasInferrer) {
// Must count other Xs; pretend next Y is far away
if (xIndex == Long.MAX_VALUE) {
// ... but stop if both are done!
break;
}
yIndex = Long.MAX_VALUE;
} else {
break;
}
} else {
yIndex = yPrefs.getItemID(yPrefIndex);
}
}
} // "Center" the data. If my math is correct, this'll do it.
double result;
if (centerData) {
double meanX = sumX / count;
double meanY = sumY / count;
// double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n * meanX * meanY;
double centeredSumXY = sumXY - meanY * sumX;
// double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX * meanX;
double centeredSumX2 = sumX2 - meanX * sumX;
// double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY * meanY;
double centeredSumY2 = sumY2 - meanY * sumY;
result = computeResult(count, centeredSumXY, centeredSumX2, centeredSumY2, sumXYdiff2);
} else {
result = computeResult(count, sumXY, sumX2, sumY2, sumXYdiff2);
} if (!Double.isNaN(result)) {
result = normalizeWeightResult(result, count, cachedNumItems);
}
return result;
}
参考:
http://blog.csdn.net/v_july_v/article/details/7184318
http://blog.sina.com.cn/s/blog_73de143c010153vp.html
Apache mahout 源码阅读笔记--协同过滤, PearsonCorrelationSimilarity的更多相关文章
- Apache mahout 源码阅读笔记-DataModel之UserBaseRecommender
先来看一下使用流程: 1)拿到DataModel 2)定义相似度计算模型 PearsonCorrelationSimilarity 3)定义用户邻域计算模型 NearestNUserNeighborh ...
- Apache mahout 源码阅读笔记--DataModel之FileDataModel
要做推荐,用户行为数据是基础. 用户行为数据有哪些字段呢? mahout的DataModel支持,用户ID,ItemID是必须的,偏好值(用户对当前Item的评分),时间戳 这四个字段 {@code ...
- Apache Storm源码阅读笔记
欢迎转载,转载请注明出处. 楔子 自从建了Spark交流的QQ群之后,热情加入的同学不少,大家不仅对Spark很热衷对于Storm也是充满好奇.大家都提到一个问题就是有关storm内部实现机理的资料比 ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- 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框架源码阅读笔记2 一切的入口 index.php
上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...
- 源码阅读笔记 - 1 MSVC2015中的std::sort
大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...
随机推荐
- 彻底解决_OBJC_CLASS_$_某文件名", referenced from:问题(转)
PS: 本文为转载而来,如有冲突,请与我联系,将立即删除. 最近在使用静态库时,总是出现这个问题.下面总结一下我得解决方法: 1. .m文件没有导入 在Build Phases里的Compile ...
- 软件配置管理中的SVN
一.简单介绍 1.什么是软件配置管理 软件配置管理是指通过运行版本号控制.变更控制的规程.以及使用合适的配置管理软件.来保证全部配置项的完整性和可跟踪性. 配置管理是对工作成果的一种有效保护. 2.为 ...
- C语言 · 数的读法
基础练习 数的读法 时间限制:1.0s 内存限制:512.0MB 问题描述 Tom教授正在给研究生讲授一门关于基因的课程,有一件事情让他颇为头疼:一条染色体上有成千上万个碱基对,它们从0 ...
- asp.net 后台调用confirm
using System;using System.Web.UI; public partial class _Default : System.Web.UI.Page, IPostBackEvent ...
- 解决mac休眠睡眠异常耗电方法
备忘
- PyCharm中设置console端的字体和大小
file--->setting,选择console Font,右侧primary font即设置console端的字体和大小
- 第二百六十六节,Tornado框架-XSS处理,页码计算,页码显示
Tornado框架-XSS处理,页码计算,页码显示 Tornado框架-XSS攻击过滤 注意:Tornado框架的模板语言,读取数据已经自动处理了XSS攻击,过滤转换了危险字符 如果要使危险字符可以远 ...
- Statement和PreparedStatement都是用来发送和执行SQL语句的
Statement和PreparedStatement都是用来发送和执行SQL语句的 DriverManager管理一组驱动程序
- YII2与Thinkphp整合阿里云OSS
前言: 如果上传的文件都和网站程序源代码放在一起:那是有相当多的弊端的: 1:静态文件会占用大量带宽: 2:服务器的成本略高: 常规的做法是把php源代码放到一台服务器上:图片等静态文件放在另一台服务 ...
- (转)c++ new/delete,new[]/delete[]原理解析
转自: 推荐:http://www.cnblogs.com/hazir/p/new_and_delete.html http://blog.csdn.net/crazyboyzzx/article/d ...