Mahout实战---编写自己的相似度计算方法
Mahout本身提供了很多的相似度计算方法,如PCC,COS等。但是当需要验证自己想出来的相似度计算公式是否是好的,这时候需要自己实现相似度类。研究了Mahout-core-0.9.jar的源码后,自己实现了一篇论文上面的相似度公式。:
论文题目:An effective collaborative filtering algorithm based on user preference clustering
具体公式如下:

实现过程:具体实现参考了LogLikeHoodSimilarity类的实现
1,实现org.apache.mahout.cf.taste.similarity.UserSimilarity接口
该接口有三个方法:
public interface UserSimilarity extends Refreshable {
double userSimilarity(long userID1, long userID2) throws TasteException;
void setPreferenceInferrer(PreferenceInferrer inferrer);
void refresh(Collection<Refreshable> alreadyRefreshed);//是Refreshable的方法
}
2,void refresh(Collection<Refreshable> alreadyRefreshed);
该方法用于刷新组件(Mahout对于数据改变的时候做出的应对方法。《Mahout实战》中3.2.3节可刷新组件中提到);具体实现如下:
public void refresh(Collection<Refreshable> alreadyRefreshed) {
// TODO Auto-generated method stub
alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
RefreshHelper.maybeRefresh(alreadyRefreshed, getDataModel());
}
3,void setPreferenceInferrer(PreferenceInferrer inferrer);
这个方法我没有实现,它的作用:可以通过PreferenceInferrer 得到对未打分项的预测评分。
4,double userSimilarity(long userID1, long userID2) throws TasteException;
该方法需要根据公式实现:计算user1和user2的相似度。
在这之前需要传递一个DataModel进来(定义成类的成员变量,由构造函数传递进来)。
具体实现如下:
/**
* 实现该方法即实现了相似度计算方法
*/
public double userSimilarity(long userID1, long userID2) throws TasteException {
// TODO Auto-generated method stub
DataModel dataModel = getDataModel();
//获取用户打分项的id集合
FastIDSet prefs1 = dataModel.getItemIDsFromUser(userID1);
FastIDSet prefs2 = dataModel.getItemIDsFromUser(userID2); long prefs1Size = prefs1.size();
long prefs2Size = prefs2.size(); /*
* long intersectionSize = prefs1Size < prefs2Size ?
* prefs2.intersectionSize(prefs1) : prefs1.intersectionSize(prefs2);
*/
// 计算交集的大小和产生新的FastIDSet作为交集
FastIDSet pre_a, pre_b;// a为大的集合
FastIDSet pre_com = new FastIDSet();
if (prefs1Size < prefs2Size) {
pre_a = prefs2;
pre_b = prefs1;
} else {
pre_a = prefs1;
pre_b = prefs2;
}
int intersectionSize = 0;
Iterator<Long> iterator = pre_b.iterator();
while (iterator.hasNext()) {
long type = (long) iterator.next();
if (pre_a.contains(type)) { pre_com.add(type);
}
}
intersectionSize = pre_com.size();
// 如果交集为0,则相似度为0
if (intersectionSize == 0) {
return 0;
}
// 计算并集的大小
long unionSize = unionSize(pre_a, pre_b); // 计算userID1的平均打分
float avg_1 = avgPreferences(userID1, prefs1);
// 计算userID2的平均打分
float avg_2 = avgPreferences(userID2, prefs2); // 计算共同打分项的打分差的和
double sum = 0.0;
iterator = pre_com.iterator();
while (iterator.hasNext()) {
long itemID = iterator.next();
sum += Math
.abs(dataModel.getPreferenceValue(userID1, itemID) - dataModel.getPreferenceValue(userID2, itemID));
}
return Math.exp(-((sum * 1.0) / intersectionSize) * Math.abs(avg_1 - avg_2))
* ((intersectionSize * 1.0) / unionSize);
}
/**
* FastIDSet只实现了intersectionSize(求交集), 现实现求并
*/
private int unionSize(FastIDSet a, FastIDSet b) {
int count = a.size();
Iterator<Long> iterator = b.iterator();
while (iterator.hasNext()) {
long type = (long) iterator.next();
if (!a.contains(type)) {
count++;
}
}
return count;
} /**
* 计算用户的打分平均值
*
* @throws TasteException
*/
private float avgPreferences(long userID, FastIDSet set) throws TasteException {
float score = (float) 0.0;
Iterator<Long> iterator = set.iterator();
while (iterator.hasNext()) {
long type = (long) iterator.next();
score += dataModel.getPreferenceValue(userID, type);
}
return score / set.size();
}
5,测试实现的正确性
根据论文的测试数据对实现的正确性进行测试

生成ups.csv
1,101,1.0
1,102,2.0
1,104,3.0
1,105,2.0
1,107,2.0 2,101,2.0
2,102,4.0
2,103,4.0
2,105,4.0
2,108,2.0
2,109,3.0 3,101,5.0
3,102,5.0
3,104,4.0
3,106,4.0
3,107,3.0
3,109,4.0 4,101,5.0
4,103,5.0
4,104,4.0
4,105,4.0
4,107,4.0
4,108,4.0 5,101,1.0
5,105,2.0
5,109,2.0
测试程序如下:
public class UPSTest {
public static void main(String[] args) throws IOException, TasteException {
String projectDir = System.getProperty("user.dir");
DataModel model = new FileDataModel(new File(projectDir + "/src/main/ups.csv"));
UserSimilarity similarity = new UPSSimiliarity(model);
DecimalFormat df = new DecimalFormat("#,##0.0000");// 保留4位小数
System.out.println(df.format(similarity.userSimilarity(1, 2)));
System.out.println(df.format(similarity.userSimilarity(1, 3)));
System.out.println(df.format(similarity.userSimilarity(1, 4)));
System.out.println(df.format(similarity.userSimilarity(1, 5)));
System.out.println(df.format(similarity.userSimilarity(2, 3)));
System.out.println(df.format(similarity.userSimilarity(2, 4)));
System.out.println(df.format(similarity.userSimilarity(2, 5)));
System.out.println(df.format(similarity.userSimilarity(3, 4)));
System.out.println(df.format(similarity.userSimilarity(3, 5)));
System.out.println(df.format(similarity.userSimilarity(4, 5)));
}
}
运行结果如下:

与论文中的结果基本相同:

参考 论文:[1] Zhang, Jia, et al. "An effective collaborative filtering algorithm based on user preference clustering." Applied Intelligence (2016): 1-11.
[2] Mahout实战
Mahout实战---编写自己的相似度计算方法的更多相关文章
- hadoop Mahout中相似度计算方法介绍(转)
来自:http://blog.csdn.net/samxx8/article/details/7691868 相似距离(距离越小值越大) 优点 缺点 取值范围 PearsonCorrelation 类 ...
- 《mahout实战》
<mahout实战> 基本信息 原书名:Mahout in action 作者: (美)Sean Owen Robin Anil Ted Dunning Ellen Fr ...
- Mahout实战---运行第一个推荐引擎
创建输入 创建intro.csv文件,内容如下 1,101,5.0 1,102,3.0 1,103,2.5 2,101,2.0 2,102,2.5 2,103,5.0 2,104,2.0 3,101, ...
- Mahout实战---评估推荐程序
推荐程序的一般评测标准有MAE(平均绝对误差),Precision(查准率),recall(查全率) 针对Mahout实战---运行第一个推荐引擎 的推荐程序,将使用上面三个标准分别测量 MAE(平均 ...
- Mahout的taste里的几种相似度计算方法
欧几里德相似度(Euclidean Distance) 最初用于计算欧几里德空间中两个点的距离,以两个用户x和y为例子,看成是n维空间的两个向量x和y, xi表示用户x对itemi的喜好值,yi表示 ...
- Dapr 与 NestJs ,实战编写一个 Pub & Sub 装饰器
Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架.Dapr 确保开发人员专注 ...
- 大规模向量相似度计算方法(Google在07年发表的文章)
转载请注明出处:http://www.cnblogs.com/zz-boy/p/3648878.html 更多精彩文章在:http://www.cnblogs.com/zz-boy/ 最近看了Goog ...
- McCabe环路复杂度计算方法
环路复杂度用来定量度量程序的逻辑复杂度.以McCabe方法来表示. 在程序控制流程图中,节点是程序中代码的最小单元,边代表节点间的程序流.一个有e条边和n个节点的流程图F,可以用下述3种方法中的任何一 ...
- 专项测试实战 | 如何测试 App 流畅度(基于 FPS 和丢帧率)
本文为霍格沃兹测试学院学员学习笔记. FPS 和丢帧率可以在一定程度上作为 APP 流畅度的一项衡量标准,本文介绍利用 adb shell dumpsys gfxinfo 命令获取软件渲染加载过程的数 ...
随机推荐
- C++ sort()函数的用法
C++sort()函数的用法 C++sort()函数的用法 近来看了c++标准库这本书,学到了很多,就把这其中的一点C++sort()函数的用法写下来和大家分享吧! (一)为什么要用c++标准库里的排 ...
- hdu 5062 单峰数(12321)的个数
http://acm.hdu.edu.cn/showproblem.php?pid=5062 模拟筛出对称单峰数(12321)的个数,水题 #include <cstdio> #inclu ...
- C++虚函数表(vtbl)
C++的虚函数的作用就是为了实现多态的机制,利用内存的指针偏移来实现将基类型的指针指向的内存空间用子类对象来初始化.这样经过内部虚表的运作,实现可以通过基类指针来调用子类所定义的方法. 这种技术,其实 ...
- NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(转载)
原文地址:http://www.cnblogs.com/asxinyu/p/dotnet_Opensource_project_FluentValidation_1.html 阅读目录 1.基本介绍 ...
- SQLite3动态库、静态库编译
资源准备 1.下载SQLite3源码,下载地址为https://www.sqlite.org/download.html.下载sqlite-amalgamation-3200000.zip和sqlit ...
- xlsxwriter
xlsxwriter是python中用来处理execl表格的库 参考
- Team Foundation Server (TFS) 2017 团队资源管理器
在千呼万唤中,TFS 2017团队资源管理器终于发布了,对于所有TFS系统的用户,都是一个天大的喜讯,尤其是对于不经常做.NET开发的团队成员. 大家都知道,伴随TFS 2013(和之前的版本)的发布 ...
- ASP.NET开发常用简单实用的方法
ASP.NET开发简单实用的方法 一.打印和导出 打印和导出EXCEL在目前ASP.NET开发中可以说是必要的,有时候针对不同数据难易程度下,用有效快速的方法是解决办法的有效途径之一. 1.打印 后台 ...
- SQL Server 维护计划(数据库备份)
公司的项目都需要定期备份,程序备份关掉iis站点复制文件就可以了,难受的地方就是数据库的备份了.服务器上装的大都是英文版,一看见英文,操作都变得小心翼翼起来,生怕哪里搞错,第二天就要被安排写辞职申请了 ...
- 记录一下将SqlLocalDb数据迁移到Sql Server Express2017的过程!
当初为了开发方便,使用了SqlLocalDb,然后再测试期产生了很多有用的数据,客户说不能删除了.麻烦 先将数据库文件下载回来,然后安装SSMS,在连接数据库地址那里,填写“(LocalDB)\MSS ...