1. 背景
在数据爆炸我们每天被数据困扰的今天,数据量发生指数级的增长,每一年产生的大数据是过去历史的总和。那么在茫茫数据大海中,对于数据生产者,怎么将自己的信息精准投放给所需的用户呢?而对于数据消费者,怎么从海量数据中快速获取自己需要的信息呢?这时推荐引擎应运而生。
推荐应用其实已经走进我们的生活,典型的推荐应用:
a. 豆瓣网站
豆瓣根据我的读书列表,及相应评论,为我推荐出如下结果:
b. 购物网站
亚马孙根据我的购书清单和相应书评,为我推荐的如下结果:
1.1 问题抽象
我们可以把推荐模型进行数据的抽象,假设有1,2,3,4和5个用户分别各自购买了101,102,103至107物品中的物品,并对其进行了各自购买的物品进行评分,那么推荐引擎如何根据用户喜好,推荐他们各自未买的物品呢?如下数据集:
2. 推荐引擎背景及算法
如果你最近想看电影,你可能咨询周围的人,而且通常你更倾向询问与“兴趣相投”的人,从他们的口味中,得出一个最近电影排名集,来敲定你想看的电影,这是协同过滤的基本思想。图解:
算法具体解决的两个问题:
a. 如何找到“兴趣相投的”人群,形成一个群体,我们称之为邻域“neighborhood“。
b. 如何从既定的邻域中,排序出喜好的项目列表?
2.1 相似度
如果我们把每个用户的评分列表看成一个一维度向量,那么可以根据向量的相似度定量化用户之间的相似性。相似度分类主要有:
a. 基于欧几里德距离计算相似度
b. 基于 Cosine 相似度
c. 基于皮尔逊相关系数计算相似度
d. 基于 Tanimoto 系数计算相似度
2.2 邻域
物以类聚,既然我们获取了用户之间的相似度值,那么那些人群归为一个邻域呢?通常有两种方法:
a. 规定 Fix-size,根据相似度值排名,取前fix-size的个数作为一个邻域
b. 规定threshold,相似度值大于规定值归为一个邻域
2.3 推荐值计算
定量的计算推测用户a对某个物品v的喜好程度,公式如下: ΣSim(i,j)Vi
即为其它各位用户对物品v的评分值的线性加权平均,其中,权重是相似度值sim,v表示对各物品的评分。
所以整个计算的过程是通过2.1和2.2解决问题a,然后根据2.3解决问题b的过程。
2.4 推荐算法分类
典型的推荐算法有:基于用户的推荐和基于物品的推荐两种。
上述的思路从基于用户的推荐方法讲解的,而在实际电商网站应用中,由于物品数量是远远大于每位用户的购买数量的,而且用户之间购买的物品重叠性较低,很难找到邻域。这时,可以换个从商品的角度思考,商品间的相似性。根据用户购物历史偏好,计算物品间的相似性,流程和基于用户的推荐一样。
3. mahout协同过滤的应用接口
3.1 相似度
相似度接口有UserSimilarity和ItemSimilarity,其主要方法如下:
double userSimilarity(long userID1, long userID2)
double itemSimilarity(long itemID1, long itemID2)
其继承类分别:
a. PearsonCorrelationSimilarity:基于皮尔逊相关系数计算相似度
b. EuclideanDistanceSimilarity:基于欧几里德距离计算相似度
c. TanimotoCoefficientSimilarity:基于 Tanimoto 系数计算相似度
d. UncerteredCosineSimilarity:计算 Cosine 相似度
3.2 邻域
邻域类UserNeighborhood,其主要接口如下:
long[] getUserNeighborhood(long userID)
输入给定用户,给出与其相似的用户列表
其继承类分别:
a. NearestNUserNeighborhood:对每个用户取固定数量 N 的最近邻居
b. ThresholdUserNeighborhood:对每个用户基于一定的限制,取落在相似度门限内的所有用户为邻居。
3.3 Recommender
关联数据模型和相似度算法模型,进行具体的计算,接口如下:
List<RecommendedItem> recommend(long userID, int howMany)
给定用户id和推荐的结果个数,返回推荐的结果
3.4 各类图关系如下:
4. 代码样例和推荐结果
4.1 mahout代码样例
public static void main(String[] args) throws IOException, TasteException { // TODO Auto-generated method stub System.out.println("starting "); String file = "item.csv"; DataModel model = new FileDataModel(new File(file)); System.out.println("starting userCF "); userCF(model); System.out.println(); System.out.println("starting itemCF"); itemCF(model); } public static void userCF(DataModel model) { try { UserSimilarity user = new UncenteredCosineSimilarity(model); NearestNUserNeighborhood neighbor = new NearestNUserNeighborhood(NEIGHBORHOOD_NUM, user, model); Recommender r = new GenericUserBasedRecommender(model, neighbor, user); LongPrimitiveIterator iter = model.getUserIDs(); while (iter.hasNext()) { long uid = iter.nextLong(); List<RecommendedItem> list = r.recommend(uid, RECOMMENDER_NUM); System.out.printf("user:%s", uid); for (RecommendedItem rItem : list) { System.out.printf("(%s,%f)", rItem.getItemID(), rItem.getValue()); } System.out.println(); } } catch (TasteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void itemCF(DataModel dataModel) { try { ItemSimilarity itemSimilarity = new UncenteredCosineSimilarity(dataModel); Recommender recommender = new GenericItemBasedRecommender(dataModel, itemSimilarity); Recommender cachingRecommender = new CachingRecommender(recommender); LongPrimitiveIterator iter = dataModel.getUserIDs(); while (iter.hasNext()) { long uid = iter.nextLong(); List<RecommendedItem> list = cachingRecommender.recommend(uid, RECOMMENDER_NUM); System.out.printf("user:%s", uid); for (RecommendedItem rItem : list) { System.out.printf("(%s,%f)", rItem.getItemID(), rItem.getValue()); } System.out.println(); } } catch (TasteException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
4.2 推荐结果
5. 评估标准
结果推荐出来,自然需要一套标准评判各自方法推荐的结果好坏。评价标准可以参考http://blog.fens.me/mahout-recommendation-api/#gsc.tab=0的2节。
参考:
1. http://en.wikipedia.org/wiki/Collaborative_filtering
2. http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy1/
3. https://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy2/
4. http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy3/