协同过滤算法——推荐引擎比你更了解你自己


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/

5. http://blog.csdn.net/huagong_adu/article/details/7362908

6. http://blog.fens.me/mahout-recommendation-api/#gsc.tab=0

posted @ 2014-01-12 18:32  gisorange  阅读(3810)  评论(0编辑  收藏  举报