GenericUserBasedRecommender: 基于用户的推荐,用户数量相对较少时速度较快。
GenericItemBasedRecommender:基于物品的推荐,物品数量较少时速度较快,外部提供了物品相似度数据后会更加有效率。
SlopeOneRecommender:基于slope-one算法(想想那个填空的表格吧)的推荐,在线推荐或更新比较快,需要先下大量的预处理运算。物品数量相对较少时使用比较合适。
SVDRecommender:效果不错,和slope-one一样,事先需要大量的预处理运算。
KnnItemBasedRecommender:基于最近邻算法的推荐器,物品数量较小时表现良好。
TreeClusteringRecommender:基于聚类的推荐器,在线推荐较快,同时也需要事先大量预处理运算,用户数量相对较少时表现良好。
准备开始看Mahout in action~
Mahout是Java写的知名推荐系统工具之一,看的目的不是使用Mahout,目的是通过这份资料了解Mahout是怎么做的。
首先看第二章,推荐系统介绍。
Mahout可以处理的User ID和Item ID需要是整数,打分(Preference)可以是任意数值,大的数值代表更喜欢。
输入文件需要是csv格式,每行三个数字分别代表:User ID, Item ID, Preference
例如
1,101,5.0 2,101,2.0
代表1号用户给101号物品打5.0分,2号用户给101号物品打2.0分。
有了数据文件,就可以利用Mahout写一个简单的推荐系统代码了。
DataModel model = new FileDataModel(new File("intro.csv"));
//建立DataModel对象存储数据文件
UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
//计算用户相似度矩阵
UserNeighborhood neighborhood = new NearestNUserNeighborhood (2, similarity, model);
//对每个用户找出2个最相似用户
Recommender recommender =
new GenericUserBasedRecommender(model, neighborhood, similarity);
//建立UserCF推荐系统
List<RecommendedItem> recommendations = recommender.recommend(1, 1);
//为用户1推荐1个Item
以上是一个简单例子,留个印象,可以先不用纠结。
然后就是需要一个推荐系统精确度衡量标准,衡量标准有MAE(误差绝对值的平均值)和RMSE(误差平方求平均再开根)等。
可以同样看一个简单例子,Mahout衡量推荐系统精确度的
RandomUtils.useTestSeed();
//用来使得每次随机都一样,仅限用于测试,不要在实际中使用
DataModel model = new FileDataModel(new File("intro.csv"));
RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
//使用MAE作为衡量标准,如果用RMSE则是 RMSRecommenderEvaluator
RecommenderBuilder builder = new RecommenderBuilder() {
@Override
public Recommender buildRecommender(DataModel model) throws TasteException {
UserSimilarity similarity = new PearsonCorrelationSimilarity (model);
UserNeighborhood neighborhood = new NearestNUserNeighborhood (2, similarity, model);
return new GenericUserBasedRecommender (model, neighborhood, similarity);
}
};
double score = evaluator.evaluate(builder, null, model, 0.7, 1.0);
//随机使用70%数据做为训练,另外30%作为测试,
//最后一个参数1.0表示使用全部的数据,如果数据太大,
//可以只用一部分数据去近似衡量推荐系统准确度,
//在仅有小改动之后做部分数据测试比较快捷。
然后除了这种精确度衡量方式,Mahout还提供其他方式。这主要是因为:在实际推荐系统中,很多情况下并没有必要准确预测打分,而只需要对待推荐物品排序,由最好到最差,就足够了。另外还有一个原因是,对于部分问题,输入数据是布尔类型的,也即我们只知道用户是否偏好,但是没有打分。
Mahout提供了精确率(Precision)和召回率(recall)两种方案:精确率是指推荐排名前列中,有多少是好的推荐(good recommendation);召回率是指好的推荐中,有多少个排在推荐排名前列。
这样我们还需要定义什么是好的推荐。
先来看看代码:
RecommenderIRStatsEvaluator evaluator = new GenericRecommenderIRStatsEvaluator ();
IRStatistics stats = evaluator.evaluate(
recommenderBuilder, null, model, null, 2, //推荐2个,计算准确率和召回率
GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD,
1.0);
System.out.println(stats.getPrecision());//输出准确率
System.out.println(stats.getRecall()); //输出召回率
假设有这样的一组数据
5,101,4.0 5,102,3.0 5,103,2.0 5,104,4.0 5,105,3.5 5,106,4.0
再假设前三行出现在测试集中,则由于101物品的分数高,所以他是好的推荐(good recommendation),而102和103都是有效的,但不是好的。但是这又有一个问题,分数到多少算分数高?你可以传进一个参数自己指定一个阈值(threshold),也可以让系统指定。
系统指定阈值的方案为:计算用户打分的均值和标准差,则阈值=均值+标准差。这样通常有大约16%的打分被选中(假设打分呈正态分布)。
文中指出了这种方式存在的问题,推荐的物品其实并不必要是已知的才说明推荐得好。一个更复杂的情况是如果输入数据是布尔类型(只知道是否喜欢),则无法选择阈值,只能是从喜欢的物品中随机选择一些用于测试。
文中还使用了GroupLens数据实际测试做例子,这里就不关注了。
运行一个RecommenderIRStatsEvaluator
Mahout提供了一个简单的途径去计算推荐器的精度等值.
可以试着运行一下代码
RandomUtils.useTestSeed();
DataModel model = new FileDataModel(new File("intro.csv"));
RecommenderIRStatsEvaluator evaluator =
new GenericRecommenderIRStatsEvaluator();
RecommenderBuilder recommenderBuilder = new RecommenderBuilder() {
@Override
public Recommender buildRecommender(DataModel model)
throws TasteException {
UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
UserNeighborhood neighborhood =
new NearestNUserNeighborhood(2, similarity, model);
return
new GenericUserBasedRecommender(model, neighborhood, similarity);
}
};
IRStatistics stats = evaluator.evaluate(
recommenderBuilder, null, model, null, 2,
GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD,
1.0); A
System.out.println(stats.getPrecision());
System.out.println(stats.getRecall());