Mahout推荐算法ItemBased
Mahout推荐的ItemBased
一、 算法原理
(一) 基本的
下面的例子,参见图评分矩阵:表现user,归类为item.
图(1)
该算法的原理:
1. 计算Item之间的相似度。
2. 对用户U做推荐
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXVleWVkZWFp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
公式(一)
Map tmp ;
Map tmp1 ;
for(item a in userRatedItems){
rate =userforItemRate(a)
ListsimItem =getSimItem(a);
For(Jin simItem){
Item b =j;
Simab=sim(a,b);
Tmp.add(b,Tmp .get(b)+simab*rate)
tmp1.add(b, tmp1.get(b)+simab)
}
}
Maptmp2=temp/temp1
Sortbyval(tmp2)
return topK(tmp2,k)
(二) 相似度计算
1. Cos相似度
公式(二)
2. 皮尔逊相似度
公式(三)
3. 调整的cos相似度
公式(四)
(三) 採样
计算全量的itemPair之间的相似度耗费大量的时间。也是没有必要的,所以须要採样,减小计算量。
二、 单机模式实现
(一) 候选Item搜索
计算全部Item Pair之间的相似度在单机模式下是不现实的,须要在海量的候选集中搜索出一部分最有可能的候选集用于计算。
Mahout提供了4中候选Item选择策略。
1. AllSimilarItemsCandidateItemsStrategy
|
@Override FastIDSet doGetCandidateItems(long[] preferredItemIDs, DataModel dataModel) throws TasteException { FastIDSet candidateItemIDs = new FastIDSet(); for (long itemID : preferredItemIDs) { candidateItemIDs.addAll(similarity.allSimilarItemIDs(itemID)); } candidateItemIDs.removeAll(preferredItemIDs); return candidateItemIDs; } |
2. AllUnknownItemsCandidateItemsStrategy
|
@Override protected FastIDSet doGetCandidateItems(long[] preferredItemIDs, DataModel dataModel) throws TasteException { FastIDSet possibleItemIDs = new FastIDSet(dataModel.getNumItems()); LongPrimitiveIterator allItemIDs = dataModel.getItemIDs(); while (allItemIDs.hasNext()) { possibleItemIDs.add(allItemIDs.nextLong()); } possibleItemIDs.removeAll(preferredItemIDs); return possibleItemIDs; } |
3. PreferredItemsNeighborhoodCandidateItemsStrategy
|
@Override protected FastIDSet doGetCandidateItems(long[] preferredItemIDs, DataModel dataModel) throws TasteException { FastIDSet possibleItemsIDs = new FastIDSet(); for (long itemID : preferredItemIDs) { PreferenceArray itemPreferences = dataModel.getPreferencesForItem(itemID); int numUsersPreferringItem = itemPreferences.length(); for (int index = 0; index < numUsersPreferringItem; index++) { possibleItemsIDs.addAll(dataModel.getItemIDsFromUser(itemPreferences.getUserID(index))); } } possibleItemsIDs.removeAll(preferredItemIDs); return possibleItemsIDs; } |
4. SamplingCandidateItemsStrategy
|
private static int computeMaxFrom(int factor, int numThings) { if (factor == NO_LIMIT_FACTOR) { return MAX_LIMIT; } long max = (long) (factor * (1.0 + Math.log(numThings) / LOG2)); return max > MAX_LIMIT ? MAX_LIMIT : (int) max; } @Override protected FastIDSet doGetCandidateItems(long[] preferredItemIDs, DataModel dataModel) throws TasteException { LongPrimitiveIterator preferredItemIDsIterator = new LongPrimitiveArrayIterator(preferredItemIDs); if (preferredItemIDs.length > maxItems) { double samplingRate = (double) maxItems / preferredItemIDs.length; // log.info("preferredItemIDs.length {}, samplingRate {}", preferredItemIDs.length, samplingRate); preferredItemIDsIterator = new SamplingLongPrimitiveIterator(preferredItemIDsIterator, samplingRate); } FastIDSet possibleItemsIDs = new FastIDSet(); while (preferredItemIDsIterator.hasNext()) { long itemID = preferredItemIDsIterator.nextLong(); PreferenceArray prefs = dataModel.getPreferencesForItem(itemID); int prefsLength = prefs.length(); if (prefsLength > maxUsersPerItem) { Iterator<Preference> sampledPrefs = new FixedSizeSamplingIterator<Preference>(maxUsersPerItem, prefs.iterator()); while (sampledPrefs.hasNext()) { addSomeOf(possibleItemsIDs, dataModel.getItemIDsFromUser(sampledPrefs.next().getUserID())); } } else { for (int i = 0; i < prefsLength; i++) { addSomeOf(possibleItemsIDs, dataModel.getItemIDsFromUser(prefs.getUserID(i))); } } } possibleItemsIDs.removeAll(preferredItemIDs); return possibleItemsIDs; } private void addSomeOf(FastIDSet possibleItemIDs, FastIDSet itemIDs) { if (itemIDs.size() > maxItemsPerUser) { LongPrimitiveIterator it = new SamplingLongPrimitiveIterator(itemIDs.iterator(), (double) maxItemsPerUser / itemIDs.size()); while (it.hasNext()) { possibleItemIDs.add(it.nextLong()); } } else { possibleItemIDs.addAll(itemIDs); } } |
(二) 估值
|
protected float doEstimatePreference(long userID, PreferenceArray preferencesFromUser, long itemID) throws TasteException { double preference = 0.0; double totalSimilarity = 0.0; int count = 0; double[] similarities = similarity.itemSimilarities(itemID, preferencesFromUser.getIDs()); for (int i = 0; i < similarities.length; i++) { double theSimilarity = similarities[i]; if (!Double.isNaN(theSimilarity)) { // Weights can be negative! preference += theSimilarity * preferencesFromUser.getValue(i); 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. 依据历史评分列表推荐
这样的推荐方式依据用户之前产生过评分的item做推荐。推荐结果依照预计值的大小排序。
|
@Override public List<RecommendedItem> recommend(long userID, Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); log.debug("Recommending items for user ID '{}'", userID); PreferenceArray preferencesFromUser = getDataModel().getPreferencesFromUser(userID); if (preferencesFromUser.length() == 0) { return Collections.emptyList(); } FastIDSet possibleItemIDs = getAllOtherItems(userID, preferencesFromUser); TopItems.Estimator<Long> estimator = new Estimator(userID, preferencesFromUser); List<RecommendedItem> topItems = TopItems.getTopItems(howMany, possibleItemIDs.iterator(), rescorer, estimator); log.debug("Recommendations are: {}", topItems); return topItems; } |
2. Because推荐
这样的推荐方式用于实时推荐。
|
@Override public List<RecommendedItem> recommendedBecause(long userID, long itemID, int howMany) throws TasteException { Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); DataModel model = getDataModel(); TopItems.Estimator<Long> estimator = new RecommendedBecauseEstimator(userID, itemID); PreferenceArray prefs = model.getPreferencesFromUser(userID); int size = prefs.length(); FastIDSet allUserItems = new FastIDSet(size); for (int i = 0; i < size; i++) { allUserItems.add(prefs.getItemID(i)); } allUserItems.remove(itemID); return TopItems.getTopItems(howMany, allUserItems.iterator(), null, estimator); } //估值方法 @Override public double estimate(Long itemID) throws TasteException { Float pref = getDataModel().getPreferenceValue(userID, itemID); if (pref == null) { return Float.NaN; } double similarityValue = similarity.itemSimilarity(recommendedItemID, itemID); return (1.0 + similarityValue) * pref; } |
三、 MapReduce模式实现
(一) 将偏好文件转换成评分矩阵(PreparePreferenceMatrixJob)
(二) 计算共现矩阵相似度(RowSimilarityJob)
(三) 挑选最相似的K个Item
(四) 用户偏好向量和相似降维后的共现矩阵做乘法
(五) 过滤制定的user\titem
(六) 生成终于的推荐结果
四、 实例演示
1. 单机模式
1) 批量推荐
|
DataModel dataModel = ItemSimilarity similarity = new PearsonCorrelationSimilarity(dataModel); ItemBasedRecommender recommender = new GenericItemBasedRecommender(dataModel,similarity ); System.out.println(recommender.recommend(10, 10)); |
2) Because推荐
|
DataModel dataModel = new FileDataModel(new File("p/pereference")); ItemSimilarity similarity = new PearsonCorrelationSimilarity(dataModel); ItemBasedRecommender recommender = new GenericItemBasedRecommender(dataModel,similarity ); System.out.println(recommender.recommendedBecause(10, 10328, 100)); |
2. MapReduce模式
API
|
org.apache.mahout.cf.taste.hadoop.item.RecommenderJob.main(args) |
|
|
--input |
偏好数据路径,文本文件。 格式 userid\t itemid\t preference |
|
--output |
推荐结果路径 |
|
-- numRecommendations |
推荐个数 |
|
--usersFile |
须要做出推荐的user,默认所有做推荐 |
|
--itemsFile |
须要做出推荐的item,默认所有做推荐 |
|
--filterFile |
文件格式文本。userid\itemid 。目的是给userid的用户不要推荐itemid的item |
|
--booleanData |
是否是布尔数据 |
|
--maxPrefsPerUser |
最大偏好值 |
|
--minPrefsPerUser |
最小偏好值 |
|
--maxSimilaritiesPerItem |
给每个Item计算最多的相似item数目 |
|
--maxPrefsPerUserInItemSimilarity |
ItemSimilarity预计item相似度时,对每个user最多偏好数目 |
|
--similarityClassname |
SIMILARITY_PEARSON_CORRELATION、SIMILARITY_COOCCURRENCE、SIMILARITY_LOGLIKELIHOOD、SIMILARITY_TANIMOTO_COEFFICIENT、SIMILARITY_CITY_BLOCK、SIMILARITY_COSINE、SIMILARITY_EUCLIDEAN_DISTANCE |
|
--threshold |
删除低于该阈值的item对 |
|
--outputPathForSimilarityMatrix |
指定生成的item相似矩阵路径,文本文件,格式为 itemA \t itemB \t 相似值 |
实例
|
String [] args ={"--input","p", "--output","recommender", "--numRecommendations","10", "--outputPathForSimilarityMatrix","simMatrix", "--similarityClassname","SIMILARITY_PEARSON_CORRELATION"} org.apache.mahout.cf.taste.hadoop.item.RecommenderJob.main(args); |
五、 參考文献
1. M.Deshpandeand G. Karypis. Item-based top-n recommendation algorithms.
2. B.M.Sarwar, G. Karypis, J.A. Konstan, and J. Reidl. Item-based collaborativefiltering recommendation algorithms.
3. Item-based collaborative filtering
4. Accuratelycomputing running variance
版权声明:本文博主原创文章,博客,未经同意不得转载。
Mahout推荐算法ItemBased的更多相关文章
- Mahout推荐算法之ItemBased
Mahout推荐之ItemBased 一. 算法原理 (一) 基本原理 如下图评分矩阵所示:行为user,列为item. 图(1) 该算法的原理: 1. 计算Item之间的相似度. 2. ...
- Mahout推荐算法API详解
转载自:http://blog.fens.me/mahout-recommendation-api/ Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, ...
- Mahout推荐算法基础
转载自(http://www.geek521.com/?p=1423) Mahout推荐算法分为以下几大类 GenericUserBasedRecommender 算法: 1.基于用户的相似度 2.相 ...
- 转】Mahout推荐算法API详解
原博文出自于: http://blog.fens.me/mahout-recommendation-api/ 感谢! Posted: Oct 21, 2013 Tags: itemCFknnMahou ...
- Mahout推荐算法之SlopOne
Mahout推荐算法之SlopOne 一. 算法原理 有别于基于用户的协同过滤和基于item的协同过滤,SlopeOne采用简单的线性模型估计用户对item的评分.如下图,估计UserB对 ...
- [转]Mahout推荐算法API详解
Mahout推荐算法API详解 Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, Pig, HBase, Sqoop, Mahout, Zookeepe ...
- Mahout推荐算法API具体解释【一起学Mahout】
阅读导读: 1.mahout单机内存算法实现和分布式算法实现分别存在哪些问题? 2.算法评判标准有哪些? 3.什么会影响算法的评分? 1. Mahout推荐算法介绍 Mahout推荐算法,从数据处理能 ...
- 从源代码剖析Mahout推荐引擎
转载自:http://blog.fens.me/mahout-recommend-engine/ Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, Pi ...
- 转】从源代码剖析Mahout推荐引擎
原博文出自于: http://blog.fens.me/mahout-recommend-engine/ 感谢! 从源代码剖析Mahout推荐引擎 Hadoop家族系列文章,主要介绍Hadoop家族产 ...
随机推荐
- 让自己的软件实现拖拽打开文件(使用WM_DROPFILES消息和DragQueryFile函数)
//声明 protected procedure WMDROPFILES(var Msg : TMessage); message WM_DROPFILES; //实现 procedure TForm ...
- django中mysql数据库设置错误解决方法
刚在django中settings.py进行设置mysql数据库. 当进行执行python manage.py shell命令时会报以下错误: 只需要在settings.py中 DATABASES = ...
- kill命令"-1"这个参数到底是杀进程还是reload?(转)
kill-1:重新读取一次参数的配置文件 (类似 reload) 这句话给我的感觉是把进程杀掉后重启进程,即 reload.而我查了下 man kill,-1 对应的 signal 是 SIGHUP, ...
- Enthought科学计算,数据分析
Enthought Canopy: Easy Python Deployment Plus Integrated Analysis Environment for Scientific Computi ...
- Android开发者必须深入学习的10个应用开源项目
Android 开发又将带来新一轮热潮,很多开发者都投入到这个浪潮中去了,创造了许许多多相当优秀的应用.其中也有许许多多的开发者提供了应用开源项 目,贡献出他们的智慧和创造力.学习开源代码是掌握技术的 ...
- cocos2dx游戏开发学习笔记3-lua面向对象分析
在lua中,能够通过元表来实现类.对象.继承等.与元表相关的方法有setmetatable().__index.getmetatable().__newindex. 详细什么是元表在这里就不细说了,网 ...
- c++中sort()及qsort()的使用方法总结
当并算法具体解释请见点我 想起来自己天天排序排序,冒泡啊,二分查找啊,结果在STL中就自带了排序函数sort,qsort,总算把自己解脱了~ 所以自己总结了一下,首先看sort函数见下表: 函数名 ...
- ffplay2 android 版正式公布
项目地址:https://github.com/DeYangLiu/AndroidPlayer/ 下载链接: 看点: 支持软键盘输入和历史记录.使用了EditText和内部存储. 这里考虑了历史记录的 ...
- PHP操作Mysql中间BLOB场
1.MySQL在BLOB字段类型 BLOB场的类型用于存储二进制数据. MySQL在.BLOB它是一种类型的一系列.含有:TinyBlob.Blob.MediumBlob.LongBlob.大小上不同 ...
- mongodb分页优化
现在参与一个项目的开发,需要用java查询mongodb数据库,在这里分页用的skip sort 和limit结合,查询语句如下(已经在相关字段建立索引) DBCursor cursor = coll ...