mahout中的一个模块Taste实现了推荐引擎的功能,到网上查了一下资料,都没有任何Taste源码分析,只有自己看一看代码了,能记的就记录下来,以后用到的时候就方便了。
推荐引擎的原理是协同过滤 (Collaborative Filtering, 简称 CF),下边就用这个缩写了。
1、基于用户的CF
基于用户的 CF 的基本思想相当简单,基于用户对物品的偏好找到相邻邻居用户,然后将邻居用户喜欢的推荐给当前用户。计算上,就是将一个用户对所有物品的偏好作为一个向量 来计算用户之间的相似度,找到 K 邻居后,根据邻居的相似度权重以及他们对物品的偏好,预测当前用户没有偏好的未涉及物品,计算得到一个排序的物品列表作为推荐。
DataModel model = new FileDataModel(new File("preferences.dat")); UserSimilarity similarity = new PearsonCorrelationSimilarity(model); UserNeighborhood neighborhood = new NearestNUserNeighborhood(100, similarity, model); Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity); |
用户推荐的接口是Recommender,有很多种实现,下边我们就以 GenericUserBasedRecommender为例,分析一下mahout用户推荐的代码实现:
//这是接口Recommender的功能函数 @Override public List<RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) throws TasteException { Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); log.debug("Recommending items for user ID '{}'", userID); //得到userid的所有howMany个相邻的user long[] theNeighborhood = neighborhood.getUserNeighborhood(userID); if (theNeighborhood.length == 0) { return Collections.emptyList(); } //先得到userid的所有邻居用户评价过的item列表, //然后在这个所有邻居评价过的item中去除掉userid评价过的item,剩下的item为allItemmIDs FastIDSet allItemIDs = getAllOtherItems(theNeighborhood, userID); //在给定的用户userid和该用户的邻居用户情况下,输入某一个item(物品),这些邻居对这个物品的评分的 //平均值,就是userid用户对该item的评分的估测值 TopItems.Estimator<Long> estimator = new Estimator(userID, theNeighborhood); //将上边allItemmIDs中的item逐个用Estimator进行估测评分,然后选出howMany得分最高的返回 List<RecommendedItem> topItems = TopItems .getTopItems(howMany, allItemIDs.iterator(), rescorer, estimator); log.debug("Recommendations are: {}", topItems); return topItems; }
从上边的代码实现,可以看到基于用户的CF分为以下几步:
1、给定一个userid的用户,获取该用户的邻居用户
long[] theNeighborhood = neighborhood.getUserNeighborhood(userID);
2、得到了邻居用户,我们从数据源中得到这些邻居用户所评价过的所有item的列表,然后再从这个列表中把userid用户评价过的item去除掉,剩下的就是userid没评价过但他的邻居评价过的item
FastIDSet allItemIDs = getAllOtherItems(theNeighborhood, userID);
3、创建一个评估器Estimator,它的作用是:在给定的用户userid和该用户的邻居用户情况下,输入某一个item(物品),这些邻居对这个物品的评分的平均值,就是userid用户对该item的评分的估测值
TopItems.Estimator<Long> estimator = new Estimator(userID, theNeighborhood);
4、将所有userid没评价过但他的邻居评价过的item使用评估器进行评估,选出在评估中得分最高的howMany个item,并将这些item返回给Recommender作为推荐结果。
List<RecommendedItem> topItems = TopItems .getTopItems(howMany, allItemIDs.iterator(), rescorer, estimator);
下篇文章,分析这些步骤的细节部分