[原]Mahout 对推荐数据的抽象表示(下部分)

标签: | 发表时间:2015-10-10 22:09 | 作者:huruzun
分享到:
出处:http://blog.csdn.net/huruzun

这篇博客是延续上部分的补充: Mahout 对推荐数据的抽象表示(上部分)

处理无Preference values 数据

下面都是围绕Mahout对没有Preference values的数据的推荐。

有时进入推荐引擎的数据没有Preference values,而是只有相关联的一个userID、itemID,它们之间有多强的联系我们没有一个Preference values来量化衡量。

例如在新闻推荐中,新闻网站根据你的浏览日志来给你推荐新闻,相当于也就是给每个user 和不同类型新闻建立联系,但是这个联系强弱不是让用户去给新闻打分来建立的而是通过用户点击新闻行为进行学习而得来的。

顺便简单介绍下用户行为数据,用户行为数据最简单存在就是日志,网站运行过程记录了大量的原始日志,这些日志就是用户最原始数据存储。用户行为在个性化推荐中一般分为两种:显性反馈行为、隐性反馈行为,从字面意思就很好理解显性反馈就是用户明确表示对物品喜好的行为,比如最经典的5分评价机制和两档评分机制(喜欢/不喜欢),隐性反馈最具代表的就是页面浏览行为,通常对于这种隐性反馈系统需要学习得到user 和 item 强弱关联。

下图是摘取自Mahout in action第三章作者一个描述是否有Preference values示意图:


书中还描述了一个忽略Preference values音乐推荐场景,具体可以看第三章内容。

Mahout 中 无Preference values 代码实现

没有Preference values 可以简化我们对Preference 的表示(上部分我们详细描述了Preference 这个数据结构在Mahout中实现),这样我们可以有更好性能提升和更少的内存使用。

上部分我们用到了一个GenericDataModel类来实现DataModel,这里我们使用GenericBooleanPrefDataModel。

我们讨论类中一些方法如:getItemIDsFromUser方法会执行很快,因为实现中只需要返回已经存好的数据结构,源码如下:

 @Override
  public FastIDSet getItemIDsFromUser(long userID) throws TasteException {
    FastIDSet itemIDs = preferenceFromUsers.get(userID);
    if (itemIDs == null) {
      throw new NoSuchUserException(userID);
    }
    return itemIDs;
  }

一些方法如getPreferencesFromUser会执行比较慢,因为执行时需要new 起来新的对象而不是上部分中讲到的直接存储Preference values在PreferenceArrays返回,参考源码:

  @Override
  public PreferenceArray getPreferencesFromUser(long userID) throws NoSuchUserException {
    FastIDSet itemIDs = preferenceFromUsers.get(userID);
    if (itemIDs == null) {
      throw new NoSuchUserException(userID);
    }
    PreferenceArray prefArray = new BooleanUserPreferenceArray(itemIDs.size());
    int i = 0;
    LongPrimitiveIterator it = itemIDs.iterator();
    while (it.hasNext()) {
      prefArray.setUserID(i, userID);
      prefArray.setItemID(i, it.nextLong());
      i++;
    }
    return prefArray;
  }

大家可能会有好奇getPreferenceValue方法返回值,因为这里根本就没有Preference values,设计者统一返回1.0f

  @Override
  public Float getPreferenceValue(long userID, long itemID) throws NoSuchUserException {
    FastIDSet itemIDs = preferenceFromUsers.get(userID);
    if (itemIDs == null) {
      throw new NoSuchUserException(userID);
    }
    if (itemIDs.contains(itemID)) {
      return 1.0f;
    }
    return null;
  }

看一个简单使用GenericBooleanPrefDataModel示例程序:

package recommender;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.eval.DataModelBuilder;
import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
import org.apache.mahout.cf.taste.eval.RecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.eval.AverageAbsoluteDifferenceRecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.model.GenericBooleanPrefDataModel;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

import java.io.File;

class IREvaluatorBooleanPrefIntro1 {

  private IREvaluatorBooleanPrefIntro1() {
  }

  public static void main(String[] args) throws Exception {
    DataModel model = new GenericBooleanPrefDataModel(
        GenericBooleanPrefDataModel.toDataMap(
          new FileDataModel(new File("ua.base"))));

    RecommenderEvaluator evaluator =
      new AverageAbsoluteDifferenceRecommenderEvaluator();
    RecommenderBuilder recommenderBuilder = new RecommenderBuilder() {
      @Override
      public Recommender buildRecommender(DataModel model) throws TasteException {
        UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
        UserNeighborhood neighborhood =
          new NearestNUserNeighborhood(10, similarity, model);
        return new GenericUserBasedRecommender(model, neighborhood, similarity);
      }
    };
    DataModelBuilder modelBuilder = new DataModelBuilder() {
      @Override
      public DataModel buildDataModel(FastByIDMap<PreferenceArray> trainingData) {
        return new GenericBooleanPrefDataModel(
          GenericBooleanPrefDataModel.toDataMap(trainingData));
      }
    };
    double score = evaluator.evaluate(
        recommenderBuilder, modelBuilder, model, 0.9, 1.0);
    System.out.println(score);
  }

}

运行结果如下:

Exception in thread "main" java.lang.IllegalArgumentException: DataModel doesn't have preference values
	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:125)
	at org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity.<init>(PearsonCorrelationSimilarity.java:74)
	at org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity.<init>(PearsonCorrelationSimilarity.java:66)
	at recommender.IREvaluatorBooleanPrefIntro1$1.buildRecommender(IREvaluatorBooleanPrefIntro1.java:37)
	at org.apache.mahout.cf.taste.impl.eval.AbstractDifferenceRecommenderEvaluator.evaluate(AbstractDifferenceRecommenderEvaluator.java:125)
	at recommender.IREvaluatorBooleanPrefIntro1.main(IREvaluatorBooleanPrefIntro1.java:50)

通过抛出异常我想大家也差不多明白,一些 similarity metric 像pearson、欧式距离等在没有Preference values时是不能工作的,如果没有Preference values 这些相似性衡量标准将失去意义。但是没有Preference values同样可以计算类似IR中 precision 和 recall。

package recommender;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.eval.DataModelBuilder;
import org.apache.mahout.cf.taste.eval.IRStatistics;
import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
import org.apache.mahout.cf.taste.eval.RecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.eval.GenericRecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.model.GenericBooleanPrefDataModel;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericBooleanPrefUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.LogLikelihoodSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

import java.io.File;

class IREvaluatorBooleanPrefIntro2 {

  private IREvaluatorBooleanPrefIntro2() {
  }

  public static void main(String[] args) throws Exception {
    DataModel model = new GenericBooleanPrefDataModel(
        GenericBooleanPrefDataModel.toDataMap(
          new FileDataModel(new File("ua.base"))));

    RecommenderIRStatsEvaluator evaluator =
      new GenericRecommenderIRStatsEvaluator();
    RecommenderBuilder recommenderBuilder = new RecommenderBuilder() {
      @Override
      public Recommender buildRecommender(DataModel model) throws TasteException {
        UserSimilarity similarity = new LogLikelihoodSimilarity(model);
        UserNeighborhood neighborhood =
          new NearestNUserNeighborhood(10, similarity, model);
        return new GenericBooleanPrefUserBasedRecommender(model, neighborhood, similarity);
      }
    };
    DataModelBuilder modelBuilder = new DataModelBuilder() {
      @Override
      public DataModel buildDataModel(FastByIDMap<PreferenceArray> trainingData) {
        return new GenericBooleanPrefDataModel(
          GenericBooleanPrefDataModel.toDataMap(trainingData));
      }
    };
    IRStatistics stats = evaluator.evaluate(
        recommenderBuilder, modelBuilder, model, null, 10,
        GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD,
        1.0);
    System.out.println(stats.getPrecision());
    System.out.println(stats.getRecall());
  }
}

我们可以注意上面代码中的相似度衡量变成了:LogLikelihoodSimilarity 这个是一个不依赖具体数字来计算的相似度所以可以work。


作者:huruzun 发表于2015/10/10 22:09:41 原文链接
阅读:583 评论:1 查看评论

相关 [mahout 数据 抽象] 推荐:

[原]Mahout 对推荐数据的抽象表示(下部分)

- - huruzun的专栏
这篇博客是延续上部分的补充: Mahout 对推荐数据的抽象表示(上部分). 处理无Preference values 数据. 下面都是围绕Mahout对没有Preference values的数据的推荐. 有时进入推荐引擎的数据没有Preference values,而是只有相关联的一个userID、itemID,它们之间有多强的联系我们没有一个Preference values来量化衡量.

[原]Mahout 对推荐数据的抽象表示(上部分)

- - huruzun的专栏
学习Mahout推荐相关算法前,我们必须先要理解Mahout如何对推荐数据进行抽象表示. 首先来看下Preference,该抽象是最基本的抽象,这个抽象对象一般代表一个单独的 userID、itemID、Preference 分数,在具体实现层面首先是Preference接口:. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.

Mahout介绍

- - 互联网 - ITeye博客
Mahout 是机器学习和数据挖掘的一个分布式框架,区别于其他的开源数据挖掘软件,它是基于hadoop之上的; 所以hadoop的优势就是Mahout的优势. http://mahout.apache.org/ 上说的Scalable就是指hadoop的可扩展性. Mahout用map-reduce实现了部分数据挖掘算法,解决了并行挖掘的问题.

C++ 工程实践(9):数据抽象

- roc - 博客园-陈硕的 Blog
陈硕 (giantchen_AT_gmail). 陈硕关于 C++ 工程实践的系列文章: http://blog.csdn.net/Solstice/category/802325.aspx. 排版正常的版本: http://www.cnblogs.com/Solstice/category/287661.html.

使用Mahout搭建推荐系统之入门篇2-玩转你的数据1

- - 互联网 - ITeye博客
用意: 搞推荐系统或者数据挖掘的, 对数据要绝对的敏感和熟悉, 并且热爱你的数据. 分析数据既要用统计分析那一套,又要熟悉业务发掘有趣的特征(feature). 后者有意思的多,但是因为我业务做的不多,还不太熟悉, 跪求大牛们分析业务经历. 听豆瓣上的大神"懒惰啊我"说过,有一个Nokia的比赛,有一个团队直接用陀螺仪参数就发现了性别分布,因为男生手机都放在 口袋里, 而女生往往放在包里面.

mahout部署实践

- - CSDN博客云计算推荐文章
一 下载mahout并解压. JAVA_HOME mahout运行需指定jdk的目录. MAHOUT_JAVA_HOME指定此变量可覆盖JAVA_HOME值. HADOOP_HOME  如果配置,则在hadoop分布式平台上运行,否则单机运行. HADOOP_CONF_DIR指定hadoop的配置文件目录.

mahout 实用教程之一

- - CSDN博客云计算推荐文章
mahout 实用教程 (一). 本文力求把mahout从使用的角度为读者建立一个框架,为后续的使用打下基础. 本文为原创文章转载请注明原网址 http://blog.csdn.net/comaple,谢谢. 下面首先给出源代码svn地址以及用于测试的公共数据集,大家可以下载并测试. mahout svn仓库地址: http://svn.apache.org/repos/asf/mahout/trunk.

Mahout: SVDRecommender SVD推荐算法

- -

Mahout实现的机器学习算法

- - ITeye博客
使用命令:mahout -h.   在Mahout实现的机器学习算法见下表:. EM聚类(期望最大化聚类). 并行FP Growth算法. 并行化了Watchmaker框架. 非Map-Reduce算法. 扩展了java的Collections类. Mahout最大的优点就是基于hadoop实现,把很多以前运行于单机上的算法,转化为了MapReduce模式,这样大大提升了算法可处理的数据量和处理性能.