阅读导读:

1.mahout单机内存算法实现和分布式算法实现分别存在哪些问题?

2.算法评判标准有哪些?

3.什么会影响算法的评分?











1.
Mahout推荐算法介绍

Mahout推荐算法,从数据处理能力上,能够划分为2类:

  • 单机内存算法实现
  • 基于Hadoop的分步式算法实现

1).
单机内存算法实现



  单机内存算法实现:就是在单机下执行的算法,是由cf.taste项目实现的,像我们熟悉的UserCF,ItemCF都支持单机内存执行。而且參数能够灵活配置。单机算法的基本实例。请參考文章:用Maven构建Mahout项目



  单机内存算法的问题在于,受限于单机的资源。

对于中等规模的数据,像1G,10G的数据量。有能力进行计算,可是超过100G的数据量,对于单机来说是不可能完毕的任务。



2). 基于Hadoop的分步式算法实现



  基于Hadoop的分步式算法实现:就是把单机内存算法并行化。把任务分散到多台计算机一起执行。Mahout提供了ItemCF基于Hadoop并行化算法实现。

基于Hadoop的分步式算法实现,请參考文章:Mahout分步式程序开发
基于物品的协同过滤ItemCF




  分步式并行算法的问题在于,怎样让单机算法并行化。

在单机算法中。我们仅仅须要考虑算法,数据结构,内存,CPU就够了,可是分步式算法还要额外考虑非常多的情况,比方多节点的数据合并,数据排序,网路通信的效率,节点宕机重算,数据分步式存储等等的非常多问题。

2.
算法评判标准:召回率(recall)与查准率(precision)



  Mahout提供了2个评估推荐器的指标。查准率和召回率(查全率)。这两个指标是搜索引擎中经典的度量方法。

mod=image&aid=8761&size=300x300&key=a35bd137cc083251&nocache=yes&type=fixnone" border="0" width="300" alt="" style="margin:0px; padding:0px; word-wrap:break-word; max-width:400px">

相关 不相关

检索到     A    C

未检索到   B    D

  • A:检索到的。相关的 (搜到的也想要的)
  • B:未检索到的。可是相关的 (没搜到。然而实际上想要的)
  • C:检索到的。可是不相关的 (搜到的但无用的)
  • D:未检索到的,也不相关的 (没搜到也无用的)

被检索到的越多越好,这是追求“查全率”,即A/(A+B),越大越好。

被检索到的,越相关的越多越好,不相关的越少越好,这是追求“查准率”。即A/(A+C)。越大越好。



在大规模数据集合中。这两个指标是相互制约的。当希望索引出很多其它的数据的时候,查准率就会下降,当希望索引更准确的时候,会索引更少的数据。



3.
Recommender的API接口



1). 系统环境:

  • Win7 64bit
  • Java 1.6.0_45
  • Maven 3
  • Eclipse Juno Service Release 2
  • Mahout 0.8
  • Hadoop 1.1.2

2). Recommender接口文件:

org.apache.mahout.cf.taste.recommender.Recommender.java

mod=image&aid=8814&size=300x300&key=19eeb3f38b4d1888&nocache=yes&type=fixnone" border="0" width="300" alt="" style="margin:0px; padding:0px; word-wrap:break-word; max-width:400px; color:rgb(68,68,68); font-family:Tahoma,'Microsoft Yahei',Simsun; font-size:14px; line-height:21px">

接口中方法的解释:

  • recommend(long userID, int howMany): 获得推荐结果。给userID推荐howMany个Item
  • recommend(long userID, int howMany, IDRescorer rescorer): 获得推荐结果,给userID推荐howMany个Item,能够依据rescorer对结构又一次排序。
  • estimatePreference(long userID, long itemID): 当打分为空,预计用户对物品的打分
  • setPreference(long userID, long itemID, float value): 赋值用户,物品。打分
  • removePreference(long userID, long itemID): 删除用户对物品的打分
  • getDataModel(): 提取推荐数据

通过Recommender接口,我能够猜出核心算法,应该会在子类的estimatePreference()方法中进行实现。



3). 通过继承关系到Recommender接口的子类:

mod=image&aid=8815&size=300x300&key=e8aca273b5488fb9&nocache=yes&type=fixnone" border="0" width="300" alt="" style="margin:0px; padding:0px; word-wrap:break-word; max-width:400px">

推荐算法实现类:

  • GenericUserBasedRecommender: 基于用户的推荐算法
  • GenericItemBasedRecommender: 基于物品的推荐算法
  • KnnItemBasedRecommender: 基于物品的KNN推荐算法
  • SlopeOneRecommender: Slope推荐算法
  • SVDRecommender: SVD推荐算法
  • TreeClusteringRecommender:TreeCluster推荐算法

以下将分别介绍每种算法的实现。

4.
測试程序:RecommenderTest.java



測试数据集:item.csv

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

測试程序:org.conan.mymahout.recommendation.job.RecommenderTest.java

package org.conan.mymahout.recommendation.job;



import java.io.IOException;

import java.util.List;



import org.apache.mahout.cf.taste.common.TasteException;

import org.apache.mahout.cf.taste.eval.RecommenderBuilder;

import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;

import org.apache.mahout.cf.taste.model.DataModel;

import org.apache.mahout.cf.taste.recommender.RecommendedItem;

import org.apache.mahout.common.RandomUtils;



public class RecommenderTest {



    final static int NEIGHBORHOOD_NUM = 2;

    final static int RECOMMENDER_NUM = 3;



    public static void main(String[] args) throws TasteException, IOException {

        RandomUtils.useTestSeed();

        String file = "datafile/item.csv";

        DataModel dataModel = RecommendFactory.buildDataModel(file);

        slopeOne(dataModel);

    }



    public static void userCF(DataModel dataModel) throws TasteException{}

    public static void itemCF(DataModel dataModel) throws TasteException{}

    public static void slopeOne(DataModel dataModel) throws TasteException{}



    ...

每种算法都一个单独的方法进行算法測试,如userCF(),itemCF(),slopeOne()….

5.
基于用户的协同过滤算法UserCF



  基于用户的协同过滤。通过不同用户对物品的评分来评測用户之间的相似性。基于用户之间的相似性做出推荐。

简单来讲就是:给用户推荐和他兴趣相似的其它用户喜欢的物品。



举例说明:





  基于用户的 CF 的基本思想相当简单,基于用户对物品的偏好找到相邻邻居用户,然后将邻居用户喜欢的推荐给当前用户。计算上,就是将一个用户对全部物品的偏好作为一个向量来计算用户之间的相似度。找到 K 邻居后,依据邻居的相似度权重以及他们对物品的偏好。预測当前用户没有偏好的未涉及物品。计算得到一个排序的物品列表作为推荐。图
2 给出了一个样例。对于用户 A,依据用户的历史偏好,这里仅仅计算得到一个邻居 – 用户 C。然后将用户 C 喜欢的物品 D 推荐给用户 A。

算法API: org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender

@Override

  public float estimatePreference(long userID, long itemID) throws TasteException {

    DataModel model = getDataModel();

    Float actualPref = model.getPreferenceValue(userID, itemID);

    if (actualPref != null) {

      return actualPref;

    }

    long[] theNeighborhood = neighborhood.getUserNeighborhood(userID);

    return doEstimatePreference(userID, theNeighborhood, itemID);

  }





protected float doEstimatePreference(long theUserID, long[] theNeighborhood, long itemID) throws TasteException {

    if (theNeighborhood.length == 0) {

      return Float.NaN;

    }

    DataModel dataModel = getDataModel();

    double preference = 0.0;

    double totalSimilarity = 0.0;

    int count = 0;

    for (long userID : theNeighborhood) {

      if (userID != theUserID) {

        // See GenericItemBasedRecommender.doEstimatePreference() too

        Float pref = dataModel.getPreferenceValue(userID, itemID);

        if (pref != null) {

          double theSimilarity = similarity.userSimilarity(theUserID, userID);

          if (!Double.isNaN(theSimilarity)) {

            preference += theSimilarity * pref;

            totalSimilarity += theSimilarity;

            count++;

          }

        }

      }

    }

    // Throw out the estimate if it was based on no data points, of course, but also if based on

    // just one. This is a bit of a band-aid on the 'stock' item-based algorithm for the moment.

    // The reason is that in this case the estimate is, simply, the user's rating for one item

    // that happened to have a defined similarity. The similarity score doesn't matter, and that

    // seems like a bad situation.

    if (count <= 1) {

      return Float.NaN;

    }

    float estimate = (float) (preference / totalSimilarity);

    if (capper != null) {

      estimate = capper.capEstimate(estimate);

    }

    return estimate;

  }

測试程序:

public static void userCF(DataModel dataModel) throws TasteException {

        UserSimilarity userSimilarity = RecommendFactory.userSimilarity(RecommendFactory.SIMILARITY.EUCLIDEAN, dataModel);

        UserNeighborhood userNeighborhood = RecommendFactory.userNeighborhood(RecommendFactory.NEIGHBORHOOD.NEAREST, userSimilarity, dataModel, NEIGHBORHOOD_NUM);

        RecommenderBuilder recommenderBuilder = RecommendFactory.userRecommender(userSimilarity, userNeighborhood, true);





        RecommendFactory.evaluate(RecommendFactory.EVALUATOR.AVERAGE_ABSOLUTE_DIFFERENCE, recommenderBuilder, null, dataModel, 0.7);

        RecommendFactory.statsEvaluator(recommenderBuilder, null, dataModel, 2);





        LongPrimitiveIterator iter = dataModel.getUserIDs();

        while (iter.hasNext()) {

            long uid = iter.nextLong();

            List list = recommenderBuilder.buildRecommender(dataModel).recommend(uid, RECOMMENDER_NUM);

            RecommendFactory.showItems(uid, list, true);

        }

    }

程序输出:

AVERAGE_ABSOLUTE_DIFFERENCE Evaluater Score:1.0

Recommender IR Evaluator: [Precision:0.5,Recall:0.5]

uid:1,(104,4.333333)(106,4.000000)

uid:2,(105,4.049678)

uid:3,(103,3.512787)(102,2.747869)

uid:4,(102,3.000000)

用R语言重写UserCF的实现,请參考文章:用R解析Mahout用户推荐协同过滤算法(UserCF)



6.
基于物品的协同过滤算法ItemCF



基于item的协同过滤,通过用户对不同item的评分来评測item之间的相似性,基于item之间的相似性做出推荐。简单来讲就是:给用户推荐和他之前喜欢的物品相似的物品。



举例说明:

mod=image&aid=8817&size=300x300&key=316062acdbcf9f58&nocache=yes&type=fixnone" border="0" width="300" alt="" style="margin:0px; padding:0px; word-wrap:break-word; max-width:400px">

  基于物品的 CF 的原理和基于用户的 CF 类似。仅仅是在计算邻居时採用物品本身,而不是从用户的角度,即基于用户对物品的偏好找到相似的物品,然后依据用户的历史偏好。推荐相似的物品给他。

从计算的角度看,就是将全部用户对某个物品的偏好作为一个向量来计算物品之间的相似度。得到物品的相似物品后。依据用户历史的偏好预測当前用户还没有表示偏好的物品。计算得到一个排序的物品列表作为推荐。图
3 给出了一个样例。对于物品 A,依据全部用户的历史偏好。喜欢物品 A 的用户都喜欢物品 C。得出物品 A 和物品 C 比較相似。而用户 C 喜欢物品 A,那么能够判断出用户 C 可能也喜欢物品 C。



算法API: org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender

@Override

  public float estimatePreference(long userID, long itemID) throws TasteException {

    PreferenceArray preferencesFromUser = getDataModel().getPreferencesFromUser(userID);

    Float actualPref = getPreferenceForItem(preferencesFromUser, itemID);

    if (actualPref != null) {

      return actualPref;

    }

    return doEstimatePreference(userID, preferencesFromUser, itemID);

  }



protected float doEstimatePreference(long userID, PreferenceArray preferencesFromUser, long itemID)

    throws TasteException {

    double preference = 0.0;

    double totalSimilarity = 0.0;

    int count = 0;

    double[] similarities = similarity.itemSimilarities(itemID, preferencesFromUser.getIDs());

    for (int i = 0; i < similarities.length; i++) {

      double theSimilarity = similarities;

      if (!Double.isNaN(theSimilarity)) {

        // Weights can be negative!

        preference += theSimilarity * preferencesFromUser.getValue(i);

        totalSimilarity += theSimilarity;

        count++;

      }

    }

    // Throw out the estimate if it was based on no data points, of course, but also if based on

    // just one. This is a bit of a band-aid on the 'stock' item-based algorithm for the moment.

    // The reason is that in this case the estimate is, simply, the user's rating for one item

    // that happened to have a defined similarity. The similarity score doesn't matter, and that

    // seems like a bad situation.

    if (count <= 1) {

      return Float.NaN;

    }

    float estimate = (float) (preference / totalSimilarity);

    if (capper != null) {

      estimate = capper.capEstimate(estimate);

    }

    return estimate;

  }

測试程序:

public static void itemCF(DataModel dataModel) throws TasteException {

        ItemSimilarity itemSimilarity = RecommendFactory.itemSimilarity(RecommendFactory.SIMILARITY.EUCLIDEAN, dataModel);

        RecommenderBuilder recommenderBuilder = RecommendFactory.itemRecommender(itemSimilarity, true);



        RecommendFactory.evaluate(RecommendFactory.EVALUATOR.AVERAGE_ABSOLUTE_DIFFERENCE, recommenderBuilder, null, dataModel, 0.7);

        RecommendFactory.statsEvaluator(recommenderBuilder, null, dataModel, 2);



        LongPrimitiveIterator iter = dataModel.getUserIDs();

        while (iter.hasNext()) {

            long uid = iter.nextLong();

            List list = recommenderBuilder.buildRecommender(dataModel).recommend(uid, RECOMMENDER_NUM);

            RecommendFactory.showItems(uid, list, true);

        }

    }

程序输出:

AVERAGE_ABSOLUTE_DIFFERENCE Evaluater Score:0.8676552772521973

Recommender IR Evaluator: [Precision:0.5,Recall:1.0]

uid:1,(105,3.823529)(104,3.722222)(106,3.478261)

uid:2,(106,2.984848)(105,2.537037)(107,2.000000)

uid:3,(106,3.648649)(102,3.380000)(103,3.312500)

uid:4,(107,4.722222)(105,4.313953)(102,4.025000)

uid:5,(107,3.736842)

7.
SlopeOne算法



  这个算法在mahout-0.8版本号中,已经被@Deprecated。SlopeOne是一种简单高效的协同过滤算法。通过均差计算进行评分。

1). 举例说明:

用户X。Y,Z,对于物品A,B进行打分,例如以下表,求Z对B的打分是多少?



Slope one算法觉得:平均值能够取代某两个未知个体之间的打分差异,事物A对事物B的平均差是:((5 - 4) + (4 - 2)) / 2 = 1.5,就得到Z对B的打分是,3-1.5 = 1.5。



Slope one算法将用户的评分之间的关系看作简单的线性关系:

Y = mX + b

2). 平均加权计算:

用户X。Y,Z。对于物品A,B,C进行打分,例如以下表,求Z对A的打分是多少?

mod=image&aid=8819&size=300x300&key=9d87eeb070b7ced9&nocache=yes&type=fixnone" border="0" width="300" alt="" style="margin:0px; padding:0px; word-wrap:break-word; max-width:400px; color:rgb(68,68,68); font-family:Tahoma,'Microsoft Yahei',Simsun; font-size:14px; line-height:21px">

  • 1. 计算A和B的平均差, ((5-3)+(3-4))/2=0.5
  • 2. 计算A和C的平均差, (5-2)/1=3
  • 3. Z对A的评分,通过AB得到, 2+0.5=2.5
  • 4. Z对A的评分,通过AC得到,5+3=8
  • 5. 通过加权平均计算Z对A的评分:A和B都有评价的用户数为2,A和C都有评价的用户数为1,权重为别是2和1, (2*2.5+1*8)/(2+1)=13/3=4.33
  • 通过这样的简单的方式。我们能够高速计算出一个评分项,完毕推荐过程!

算法API: org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommender

@Override

  public float estimatePreference(long userID, long itemID) throws TasteException {

    DataModel model = getDataModel();

    Float actualPref = model.getPreferenceValue(userID, itemID);

    if (actualPref != null) {

      return actualPref;

    }

    return doEstimatePreference(userID, itemID);

  }

  

  private float doEstimatePreference(long userID, long itemID) throws TasteException {

    double count = 0.0;

    double totalPreference = 0.0;

    PreferenceArray prefs = getDataModel().getPreferencesFromUser(userID);

    RunningAverage[] averages = diffStorage.getDiffs(userID, itemID, prefs);

    int size = prefs.length();

    for (int i = 0; i < size; i++) {

      RunningAverage averageDiff = averages;

      if (averageDiff != null) {

        double averageDiffValue = averageDiff.getAverage();

        if (weighted) {

          double weight = averageDiff.getCount();

          if (stdDevWeighted) {

            double stdev = ((RunningAverageAndStdDev) averageDiff).getStandardDeviation();

            if (!Double.isNaN(stdev)) {

              weight /= 1.0 + stdev;

            }

            // If stdev is NaN, then it is because count is 1. Because we're weighting by count,

            // the weight is already relatively low. We effectively assume stdev is 0.0 here and

            // that is reasonable enough. Otherwise, dividing by NaN would yield a weight of NaN

            // and disqualify this pref entirely

            // (Thanks Daemmon)

          }

          totalPreference += weight * (prefs.getValue(i) + averageDiffValue);

          count += weight;

        } else {

          totalPreference += prefs.getValue(i) + averageDiffValue;

          count += 1.0;

        }

      }

    }

    if (count <= 0.0) {

      RunningAverage itemAverage = diffStorage.getAverageItemPref(itemID);

      return itemAverage == null ? Float.NaN : (float) itemAverage.getAverage();

    } else {

      return (float) (totalPreference / count);

    }

  }

測试程序:

public static void slopeOne(DataModel dataModel) throws TasteException {

        RecommenderBuilder recommenderBuilder = RecommendFactory.slopeOneRecommender();



        RecommendFactory.evaluate(RecommendFactory.EVALUATOR.AVERAGE_ABSOLUTE_DIFFERENCE, recommenderBuilder, null, dataModel, 0.7);

        RecommendFactory.statsEvaluator(recommenderBuilder, null, dataModel, 2);



        LongPrimitiveIterator iter = dataModel.getUserIDs();

        while (iter.hasNext()) {

            long uid = iter.nextLong();

            List list = recommenderBuilder.buildRecommender(dataModel).recommend(uid, RECOMMENDER_NUM);

            RecommendFactory.showItems(uid, list, true);

        }

    }

程序输出:

AVERAGE_ABSOLUTE_DIFFERENCE Evaluater Score:1.3333333333333333

Recommender IR Evaluator: [Precision:0.25,Recall:0.5]

uid:1,(105,5.750000)(104,5.250000)(106,4.500000)

uid:2,(105,2.286115)(106,1.500000)

uid:3,(106,2.000000)(102,1.666667)(103,1.625000)

uid:4,(105,4.976859)(102,3.509071)

8.
KNN Linear interpolation item–based推荐算法

  这个算法在mahout-0.8版本号中。已经被@Deprecated。



算法API: org.apache.mahout.cf.taste.impl.recommender.knn.KnnItemBasedRecommender

@Override

  protected float doEstimatePreference(long theUserID, PreferenceArray preferencesFromUser, long itemID)

    throws TasteException {

    

    DataModel dataModel = getDataModel();

    int size = preferencesFromUser.length();

    FastIDSet possibleItemIDs = new FastIDSet(size);

    for (int i = 0; i < size; i++) {

      possibleItemIDs.add(preferencesFromUser.getItemID(i));

    }

    possibleItemIDs.remove(itemID);

    

    List mostSimilar = mostSimilarItems(itemID, possibleItemIDs.iterator(),

      neighborhoodSize, null);

    long[] theNeighborhood = new long[mostSimilar.size() + 1];

    theNeighborhood[0] = -1;

  

    List usersRatedNeighborhood = Lists.newArrayList();

    int nOffset = 0;

    for (RecommendedItem rec : mostSimilar) {

      theNeighborhood[nOffset++] = rec.getItemID();

    }

    

    if (!mostSimilar.isEmpty()) {

      theNeighborhood[mostSimilar.size()] = itemID;

      for (int i = 0; i < theNeighborhood.length; i++) {

        PreferenceArray usersNeighborhood = dataModel.getPreferencesForItem(theNeighborhood);

        int size1 = usersRatedNeighborhood.isEmpty() ? usersNeighborhood.length() : usersRatedNeighborhood.size();

        for (int j = 0; j < size1; j++) {

          if (i == 0) {

            usersRatedNeighborhood.add(usersNeighborhood.getUserID(j));

          } else {

            if (j >= usersRatedNeighborhood.size()) {

              break;

            }

            long index = usersRatedNeighborhood.get(j);

            if (!usersNeighborhood.hasPrefWithUserID(index) || index == theUserID) {

              usersRatedNeighborhood.remove(index);

              j--;

            }

          }

        }

      }

    }



    double[] weights = null;

    if (!mostSimilar.isEmpty()) {

      weights = getInterpolations(itemID, theNeighborhood, usersRatedNeighborhood);

    }

    

    int i = 0;

    double preference = 0.0;

    double totalSimilarity = 0.0;

    for (long jitem : theNeighborhood) {

      

      Float pref = dataModel.getPreferenceValue(theUserID, jitem);

      

      if (pref != null) {

        double weight = weights;

        preference += pref * weight;

        totalSimilarity += weight;

      }

      i++;      

    }

    return totalSimilarity == 0.0 ? Float.NaN : (float) (preference / totalSimilarity);

  }

}

測试程序:

public static void itemKNN(DataModel dataModel) throws TasteException {

        ItemSimilarity itemSimilarity = RecommendFactory.itemSimilarity(RecommendFactory.SIMILARITY.EUCLIDEAN, dataModel);

        RecommenderBuilder recommenderBuilder = RecommendFactory.itemKNNRecommender(itemSimilarity, new NonNegativeQuadraticOptimizer(), 10);



        RecommendFactory.evaluate(RecommendFactory.EVALUATOR.AVERAGE_ABSOLUTE_DIFFERENCE, recommenderBuilder, null, dataModel, 0.7);

        RecommendFactory.statsEvaluator(recommenderBuilder, null, dataModel, 2);



        LongPrimitiveIterator iter = dataModel.getUserIDs();

        while (iter.hasNext()) {

            long uid = iter.nextLong();

            List list = recommenderBuilder.buildRecommender(dataModel).recommend(uid, RECOMMENDER_NUM);

            RecommendFactory.showItems(uid, list, true);

        }

    }

程序输出:

AVERAGE_ABSOLUTE_DIFFERENCE Evaluater Score:1.5

Recommender IR Evaluator: [Precision:0.5,Recall:1.0]

uid:1,(107,5.000000)(104,3.501168)(106,3.498198)

uid:2,(105,2.878995)(106,2.878086)(107,2.000000)

uid:3,(103,3.667444)(102,3.667161)(106,3.667019)

uid:4,(107,4.750247)(102,4.122755)(105,4.122709)

uid:5,(107,3.833621)

9. SVD推荐算法

算法API: org.apache.mahout.cf.taste.impl.recommender.svd.SVDRecommender

@Override

  public float estimatePreference(long userID, long itemID) throws TasteException {

    double[] userFeatures = factorization.getUserFeatures(userID);

    double[] itemFeatures = factorization.getItemFeatures(itemID);

    double estimate = 0;

    for (int feature = 0; feature < userFeatures.length; feature++) {

      estimate += userFeatures[feature] * itemFeatures[feature];

    }

    return (float) estimate;

  }

測试程序:

public static void svd(DataModel dataModel) throws TasteException {

        RecommenderBuilder recommenderBuilder = RecommendFactory.svdRecommender(new ALSWRFactorizer(dataModel, 10, 0.05, 10));



        RecommendFactory.evaluate(RecommendFactory.EVALUATOR.AVERAGE_ABSOLUTE_DIFFERENCE, recommenderBuilder, null, dataModel, 0.7);

        RecommendFactory.statsEvaluator(recommenderBuilder, null, dataModel, 2);



        LongPrimitiveIterator iter = dataModel.getUserIDs();

        while (iter.hasNext()) {

            long uid = iter.nextLong();

            List list = recommenderBuilder.buildRecommender(dataModel).recommend(uid, RECOMMENDER_NUM);

            RecommendFactory.showItems(uid, list, true);

        }

    }

程序输出:

AVERAGE_ABSOLUTE_DIFFERENCE Evaluater Score:0.09990564982096355

Recommender IR Evaluator: [Precision:0.5,Recall:1.0]

uid:1,(104,4.032909)(105,3.390885)(107,1.858541)

uid:2,(105,3.761718)(106,2.951908)(107,1.561116)

uid:3,(103,5.593422)(102,2.458930)(106,-0.091259)

uid:4,(105,4.068329)(102,3.534025)(107,0.206257)

uid:5,(107,0.105169)

10.
Tree Cluster-based 推荐算法

  这个算法在mahout-0.8版本号中,已经被@Deprecated。

算法API: org.apache.mahout.cf.taste.impl.recommender.TreeClusteringRecommender

@Override

  public float estimatePreference(long userID, long itemID) throws TasteException {

    DataModel model = getDataModel();

    Float actualPref = model.getPreferenceValue(userID, itemID);

    if (actualPref != null) {

      return actualPref;

    }

    buildClusters();

    List topRecsForUser = topRecsByUserID.get(userID);

    if (topRecsForUser != null) {

      for (RecommendedItem item : topRecsForUser) {

        if (itemID == item.getItemID()) {

          return item.getValue();

        }

      }

    }

    // Hmm, we have no idea. The item is not in the user's cluster

    return Float.NaN;

  }

測试程序:

public static void treeCluster(DataModel dataModel) throws TasteException {

        UserSimilarity userSimilarity = RecommendFactory.userSimilarity(RecommendFactory.SIMILARITY.LOGLIKELIHOOD, dataModel);

        ClusterSimilarity clusterSimilarity = RecommendFactory.clusterSimilarity(RecommendFactory.SIMILARITY.FARTHEST_NEIGHBOR_CLUSTER, userSimilarity);

        RecommenderBuilder recommenderBuilder = RecommendFactory.treeClusterRecommender(clusterSimilarity, 10);

程序输出:

AVERAGE_ABSOLUTE_DIFFERENCE Evaluater Score:NaN

Recommender IR Evaluator: [Precision:NaN,Recall:0.0]

11.
Mahout推荐算法总结

算法及适用场景:



算法评分的结果:



通过对上面几种算法的一评分比較:itemCF,itemKNN,SVD的Rrecision,Recall的评分值是最好的。而且itemCF和SVD的AVERAGE_ABSOLUTE_DIFFERENCE是最低的,所以,从算法的角度知道了。哪个算法是更准确的或者会索引到很多其它的数据集。

另外的一些因素:

  • 1. 这3个指标,并不能直接决定计算结果一定itemCF,SVD好
  • 2. 各种算法的參数我们并没有调优
  • 3. 数据量和数据分布,是影响算法的评分

Mahout推荐算法API具体解释【一起学Mahout】的更多相关文章

  1. 转】Mahout推荐算法API详解

    原博文出自于: http://blog.fens.me/mahout-recommendation-api/ 感谢! Posted: Oct 21, 2013 Tags: itemCFknnMahou ...

  2. [转]Mahout推荐算法API详解

    Mahout推荐算法API详解 Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, Pig, HBase, Sqoop, Mahout, Zookeepe ...

  3. Mahout推荐算法API详解

    转载自:http://blog.fens.me/mahout-recommendation-api/ Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, ...

  4. Mahout推荐算法基础

    转载自(http://www.geek521.com/?p=1423) Mahout推荐算法分为以下几大类 GenericUserBasedRecommender 算法: 1.基于用户的相似度 2.相 ...

  5. Mahout推荐算法之SlopOne

    Mahout推荐算法之SlopOne 一.       算法原理 有别于基于用户的协同过滤和基于item的协同过滤,SlopeOne采用简单的线性模型估计用户对item的评分.如下图,估计UserB对 ...

  6. Mahout推荐算法ItemBased

    Mahout推荐的ItemBased 一.   算法原理 (一)    基本的 下面的例子,参见图评分矩阵:表现user,归类为item. 图(1) 该算法的原理: 1.  计算Item之间的相似度. ...

  7. Mahout推荐算法之ItemBased

    Mahout推荐之ItemBased 一.   算法原理 (一)    基本原理 如下图评分矩阵所示:行为user,列为item. 图(1) 该算法的原理: 1.  计算Item之间的相似度. 2.  ...

  8. Mahout构建图书推荐系统【一起学Mahout】

    阅读导读: 1.Mahout中推荐过滤算法支持哪两种算法? 2.用java代码怎样计算男性用户打分过的图书? 3.itemEuclidean.userEuclideanNoPref各自是什么算法? 1 ...

  9. 从源代码剖析Mahout推荐引擎

    转载自:http://blog.fens.me/mahout-recommend-engine/ Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, Pi ...

随机推荐

  1. AJAX 创建对象 请求 响应 readyState

    AJAX 创建对象 请求 响应 readyState AjAX = Asynchronous JavaScript and XML (异步的JavaScrip和 XML). 不是新的编程语言, 而是一 ...

  2. C#调用带结构体指针的C Dll的方法【转】

    发现一篇文章关于C#调用DALL动态链接库的函数的,复制下来学习用.感谢作者的分析,原文传送门:https://www.cnblogs.com/ye-ming/p/8004314.html 在C#中调 ...

  3. like

    5.在WHERE中使用like做模糊查询    %符号表示0到多个任意字符    _符号表示1个任意字符     //查询名字中含有O字符的员工信息   select empno,ename   fr ...

  4. apache rewrite 正則表達式基础

    用了好几次rewrite,用的次数不是非常多,每次都忘,都得又一次上网上找一堆现看,总结一下,以免以后忘了 =====================分隔符===================== ...

  5. cocos2d-x-lua基础系列教程一(hello lua)

    myscene.lua function ERROR_TRACBACK(msg) print (==========) print ("lua error is "..tostri ...

  6. App 签名过期或泄露怎么办?别担心,Google 已经给出解决方案!

    一.序 在将 App 发布到市场之前,很重要的一个步骤就是为 APK 进行签名,大部分时候,这个操作隐藏在了打包的流程中,而不被我们注意到. 签名的作用,除了证明 App 的所有权之外,还可以帮助 A ...

  7. MongoDB数据操作之删除与游标处理

    删除数据(比较常用) 范例:清空infos集合中的内容.表.文档.成员. db.infos.remove({"url":/-/}); 默认情况下都删除,第二个条件设为true,只删 ...

  8. kettle工具的设计模块

    大家都知道,每个ETL工具都用不同的名字来区分不同的组成部分.kettle也不例外. 比如,在 Kettle的四大不同环境工具 本博客,是立足于kettle工具的设计模块的概念介绍. 1.转换 转换( ...

  9. 让placeholder中的默认文字居中,或者缩进多少像素

    直接给input或者textarea的样式加texta-align:center; <input type="" name="" id="&qu ...

  10. jQuery学习(五)——使用JQ完成复选框的全选和全不选

    1.在系统后台进行人员管理时,进行批量删除,使用jq完成全选和全不选 步骤分析: 第一步:引入jquery文件 第二步:书写页面加载函数 第三步:为上面的复选框绑定单击事件 第四步:将下面所有的复选框 ...