2 推荐系统介绍

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: 2 推荐系统介绍

本章包括
Mahout里面的推荐引擎
实践第一个推荐引擎
评估推荐引擎的准确性和质量
使用GroupLens真实数据评估推荐引擎

  每天我们都对事物表达喜好,不喜欢和不关心。它无意识的发生了。你从电台听到一首歌并注意到它了,因为它吸人,或者难听或者你根本没有注意到它。同样的事发生在衬衫,沙拉,发型,面孔等。虽然人们爱好不一样,但都遵循这个模式。人们喜好和他们所喜好的类似的东西。比如某人喜欢牛肉拉面,你可以猜到他同样喜欢羊肉泡馍,因为都是清真食品。同样的,人们喜欢和他相似的人喜欢的东西。这个可以用来判定喜欢和不喜欢。推荐系统就是用来判定这些模式的爱好,被用来发现你不知道但想要的东西。在这个观点更深入的研究后,你将运行一个简单的推荐引擎并明白它怎么工作的。

2.1 定义一个推荐系统

  比如你去书架找这本书,你可以看到挨着它放的书你可能也喜欢。因为人们喜欢把相关的书放在一块儿。如果要发现你可能喜欢的东西,可以从和你有类似喜好的人喜欢的东西里面找,也可以从类似你已经拥有的东西里面去找。实际上有两类推荐算法引擎:基于用户的和基于物品的,这两者Mahout都含有。严格的讲,上述就是采用协同过滤来推荐的。这种技术不需要项的属性。也就是说,这个推荐引擎框架不关心项是书,花还是其他人,即不需要输入数据的属性。
  当然也有其它依赖与属性的算法即基于内容的推荐引擎技术。比如,你朋友推荐这本书给你是因为它是Manning的书,而你的朋友喜欢其它的Manning的书,所以你朋友喜欢什么东西更像基于内容的推荐。这种推荐就是基于书的属性:出版商。如果要实现基于内容的推荐引擎,你必须决定使用项的什么属性以及每个属性的权值,而且换个领域,算法就不行了。
基于这个原因,Mahout不想多关心基于内容的推荐引擎。Mahout提供的就是协调过滤框架。具体参见第5章关于dating网站的例子。现在我们来看一个简单的例子。

2.2 运行第一个推荐引擎

  Mahout含有多种类型的推荐引擎,我们以一个简单的基于用户的推荐引擎开始吧。

创建输入
  数据输入采用参考数据的形式,每条参考数据包含用户ID,物品ID和对应的参考值,因为我们是要把物品推荐给用户,这样表达输入数据比较合理。用户ID和物品ID是一个整形的ID,参考值是一个范围的数值,比如可以是1-5,其中数值越大表示越喜欢。
  按照这个逻辑先创建一个如下形式的输入文件intro.csv。依次为用户ID,物品ID,参考值。

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,2.5
3,104,4.0
3,105,4.5
3,107,5.0
4,101,5.0
4,103,3.0
4,104,4.5
4,106,4.0
5,101,4.0
5,102,3.0
5,103,2.0
5,104,4.0
5,105,3.5
5,106,4.0

  可以看到用户1和5具有相似的喜欢,他们都喜欢101>102>103。用户1和用户4也类似,他们都喜欢101和103。用户1和用户2好像就相反了,用户1喜欢102但是用户2不喜欢。用户1和用户3就看不出来了,因为他们重复喜欢的就只有101。

创建推荐系统
  如果要给用户1推荐,该推荐什么呢?不能是101,102和103,因为用户已经有了。推荐系统是要发现新的东西给用户1。用户4和用户5喜欢类似用户1,看来可以从他们喜欢的东西中去找到可能推荐的东西。剩下的104,105,106中,104更有可能。
  现在,运行下面的代码:

class RecommenderIntro {
	public static void main(String[] args) throws Exception {
		DataModel model = new FileDataModel(new File("intro.csv"));
		UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
		UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);
		Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity);
		List<RecommendedItem> recommendations = recommender.recommend(1, 1);
		for (RecommendedItem recommendation : recommendations) {
			System.out.println(recommendation);
		}
	}
}

  在接下来2章中将详细介绍,现在稍微解释下。DataModelimplementation存储和提供怎么去获取参考数据,UserSimilarityimplementation用来计算2个用户的相似度,UserNeighborhoodimplementation用来定义用户相似的邻居关系,最后Recommenderimplementation计算并推荐结果。

分析输出
  运行代码会有如下输出:
RecommendedItem [item:104, value:4.257081]

2.3 评估一个推荐系统

  现在我们要解决一个问题,即对一个用户来说,什么推荐系统是最好的。现在我们就要来评估推荐系统。
一个最好的推荐应该是它可以很好推荐你所没有表达喜好的物品,并对这些推荐进行评级。其实推荐系统就是估计这些参考值,所以评估这些推荐系统就可以计算它的参考值和实际值的吻合度。
训练数据和评分
  实际的参考值不存在,任何人都不可能知道,但是我们可以模通过把已有的输入数据分成真实数据和测试数据。通过推荐系统,处理分出来的真实数据,产生推荐值,然后和分出来的测试数据进行比较,差异越小的越好。这种差异的计算可以通过均值,也可以通过平方的均值。如下表所示:

Item 1 Item 2 Item 3
测试数据值 3.0 5.0 4.0
推荐数据值 3.5 2.0 5.0
差异 0.5 3.0 1.0
差异平均值 = (0.5 + 3.0 + 1.0) / 3 = 1.5
差异的平方开放值 = √((0.5^2+ 3.0^2+ 1.0^2) / 3) = 1.8484

运行推荐评估系统
参考如下代码:
代码2.3

		RandomUtils.useTestSeed();
		DataModel model = new FileDataModel(new File("intro.csv"));
		RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
		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);
		System.out.println(score);

  RecommenderEvaluator把数据分成训练数据和测试数据,构建一个数据模型和推荐系统进行测试,最好比较推荐值和实际值。

获取结果
  运行测试,输出结果为1.0。因为RandomUtils.useTestSeed(),每次使用同样的随机数,所以多次运行都能得到同一个结果,这方便测试。这儿用的是AverageAbsoluteDifferenceRecommenderEvaluator,即产生的结果是推荐值和测试值差异的均值。你也可以用RMSRecommenderEvaluator替代AverageAbsoluteDifferenceRecommenderEvaluator而得到平方开方平均值。evaluator.evaluate方法中的1.0代表需要使用的输入数据即100%,0.7表示这些输入数据中多少用于推荐计算即70%。
  更一般的说,我们可以用经典的信息检索指标来评估推荐系统:精度和重现度。就像搜索引擎从查询到的很多可能的结果中返回最好的结果一样。搜素引擎不能返回相关度不高的结果到最上面,应该返回最相关的结果。比如精度10意味着前面的结果在相关里的比例为10%,重现度表示所有相关的结果在最前的比例。用在推荐引擎上就是:精度为最前的推荐引擎是好的推荐引擎的比例,重现度是好的推荐引擎在最前的比例。

2.4 评估精度和重现能力

  运行RecommenderIRStatsEvaluator。如下代码:

		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);
		System.out.println(stats.getPrecision());
		System.out.println(stats.getRecall());

  输出应为:
0.75
1.0
  精度对用户2是0.75表示平均3/4的推荐是好的,即推荐的结果中占实际结果的75%,重现度是1.0,在他们推荐的结果中都是好的推荐,即推荐的结果中100%在实际结果中。

精度和重现能力问题

2.5 评估GroupLens数据集

  工具在手,我们不仅要讨论推荐系统的速度,而且还有质量。

分解输入
  GroupLens (http://grouplens.org/)是一个提供了不同大小数据的研究项目,每个数据集都是从真实用户的评分中获取的。到http://www.grouplens.org/node/73下载100K数据集吧,解压找到ua.base文件,它是用制表符Tab分割的数据文件。把ua.base应用与代码2.3中,通过几分钟后,你会得到结果在0.9左右。难道我们实现的推荐引擎不是最好的?
使用其它推荐系统试验
  我们用org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOne-Recommender试试吧。

                RecommenderBuilder recommenderBuilder = new RecommenderBuilder() {
			@Override
			public Recommender buildRecommender(DataModel model) throws TasteException {
				return new SlopeOneRecommender(model);
			}
		};

  再次运行,结果在0.748左右,好像更好了。每个算法都有它的优势。比如,slope-one可以更快的计算推荐,但是它需要先去计算产生内部数据结构。

2.6 总结

  本章,我们介绍了推荐引擎的概率。我们可以创建一个小量数据集的Mahout推荐引擎,运行并解释结果。评估推荐系统并解释输出。最好用真实数据评估了推荐系统。本作品采用知识共享署名 4.0 国际许可协议进行许可。

发表回复