【问题标题】:Does Mahout provide a way to determine similarity between content (for content-based recommendations)?Mahout 是否提供了一种方法来确定内容之间的相似性(用于基于内容的推荐)?
【发布时间】:2014-05-12 11:15:36
【问题描述】:

Mahout 是否提供一种方法来确定内容之间的相似性?

我想生成基于内容的推荐作为 Web 应用程序的一部分。我知道 Mahout 擅长获取用户评分矩阵并根据它们生成推荐,但我对协作(基于评分)推荐不感兴趣。我想对两段文本的匹配程度进行评分,然后推荐与我在用户个人资料中为用户存储的文本最匹配的项目...

我已阅读 Mahout 的文档,看起来它主要促进协作(基于评级)推荐,而不是基于内容的推荐......这是真的吗?

【问题讨论】:

  • 如果您喜欢下面的答案,您应该感谢某人为回答所付出的努力,并将答案标记为正确。这会阻止人们在未来帮助您。

标签: mahout recommendation-engine mahout-recommender content-based-retrieval


【解决方案1】:

这并不完全正确。 Mahout 没有基于内容的推荐器,但它确实具有基于内容计算项目之间相似性的算法。最流行的一种是 TF-IDF 和余弦相似度。然而,计算不是即时的,而是离线完成的。您需要 hadoop 更快地根据内容计算成对相似度。我要编写的步骤适用于 MAHOUT 0.8。我不确定他们是否在 0.9 中更改了它。

第 1 步。您需要将文本文档转换为 seq 文件。我在 MAHOUT-0.8 中丢失了此命令,但在 0.9 中是这样的(请检查您的 MAHOUT 版本):

$MAHOUT_HOME/bin/mahout seqdirectory
--input <PARENT DIR WHERE DOCS ARE LOCATED> --output <OUTPUT DIRECTORY>
<-c <CHARSET NAME OF THE INPUT DOCUMENTS> {UTF-8|cp1252|ascii...}>
<-chunk <MAX SIZE OF EACH CHUNK in Megabytes> 64>
<-prefix <PREFIX TO ADD TO THE DOCUMENT ID>>

第 2 步。您需要将序列文件转换为稀疏向量,如下所示:

$MAHOUT_HOME/bin/mahout seq2sparse \
   -i <SEQ INPUT DIR> \
   -o <VECTORS OUTPUT DIR> \
   -ow -chunk 100 \
   -wt tfidf \
   -x 90 \
   -seq \
   -ml 50 \
   -md 3 \
   -n 2 \
   -nv \
   -Dmapred.map.tasks=1000 -Dmapred.reduce.tasks=1000

地点:

  • chunk 是文件的大小。
  • x 术语的最大数量应被视为字典文件的一部分。如果它出现的次数少于 -x,则将其视为停用词。
  • wt 是加权方案。
  • md 术语应出现在被视为字典文件一部分的最小文档数。任何频率较低的术语都会被忽略。
  • n 在 Lp 空间中使用的归一化值。 8.4 节给出了归一化的详细解释。默认方案是不对权重进行标准化。 2 适用于余弦距离,我们将其用于聚类和相似度
  • nv to 获取命名向量,使进一步的数据文件更易于检查。

步骤 3. 从向量创建矩阵:

$MAHOUT_HOME/bin/mahout rowid -i <VECTORS OUTPUT DIR>/tfidf-vectors/part-r-00000 -o <MATRIX OUTPUT DIR>

第 4 步。为上述矩阵的每一行创建一个相似文档的集合。这将为集合中的每个文档生成 50 个最相似的文档。

 $MAHOUT_HOME/bin/mahout rowsimilarity -i <MATRIX OUTPUT DIR>/matrix -o <SIMILARITY OUTPUT DIR> -r <NUM OF COLUMNS FROM THE OUTPUT IN STEP 3> --similarityClassname SIMILARITY_COSINE -m 50 -ess -Dmapred.map.tasks=1000 -Dmapred.reduce.tasks=1000

这将生成一个文件,其中每个项目与基于内容的前 50 个文件具有相似性。

现在,要在推荐过程中使用它,您需要读取文件或将其加载到数据库中,具体取决于您拥有多少资源。我使用Collection&lt;GenericItemSimilarity.ItemItemSimilarity&gt; 加载到主内存中。以下是为我完成这项工作的两个简单函数:

public static Collection<GenericItemSimilarity.ItemItemSimilarity> correlationMatrix(final File folder, TIntLongHashMap docIndex) throws IOException{
        Collection<GenericItemSimilarity.ItemItemSimilarity> corrMatrix = 
                new ArrayList<GenericItemSimilarity.ItemItemSimilarity>();

        ItemItemSimilarity itemItemCorrelation = null;

        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(conf);

        int n=0;
        for (final File fileEntry : folder.listFiles()) {
            if (fileEntry.isFile()) {
                if(fileEntry.getName().startsWith("part-r")){

                    SequenceFile.Reader reader = new SequenceFile.Reader(fs, new Path(fileEntry.getAbsolutePath()), conf);

                    IntWritable key = new IntWritable();
                    VectorWritable value = new VectorWritable();
                    while (reader.next(key, value)) {

                        long itemID1 = docIndex.get(Integer.parseInt(key.toString()));

                        Iterator<Element> it = value.get().nonZeroes().iterator();

                        while(it.hasNext()){
                            Element next = it.next();
                            long itemID2 =  docIndex.get(next.index());
                            double similarity =  next.get();
                            //System.out.println(itemID1+ " : "+itemID2+" : "+similarity);

                            if (similarity < -1.0) {
                                similarity = -1.0;
                            } else if (similarity > 1.0) {
                                similarity = 1.0;
                            }


                            itemItemCorrelation = new GenericItemSimilarity.ItemItemSimilarity(itemID1, itemID2, similarity);

                            corrMatrix.add(itemItemCorrelation);
                        }
                    }
                    reader.close();
                    n++;
                    logger.info("File "+fileEntry.getName()+" readed ("+n+"/"+folder.listFiles().length+")");
                }
            }
        }

        return corrMatrix;
    }


public static TIntLongHashMap getDocIndex(String docIndex) throws IOException{
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(conf);

        TIntLongHashMap map = new TIntLongHashMap();
        SequenceFile.Reader docIndexReader = new SequenceFile.Reader(fs, new Path(docIndex), conf);

        IntWritable key = new IntWritable();
        Text value = new Text();
        while (docIndexReader.next(key, value)) {
            map.put(key.get(), Long.parseLong(value.toString()));
        }

        return map;
    }

最后,在您的推荐课程中,您将其称为:

TIntLongHashMap docIndex = ItemPairwiseSimilarityUtil.getDocIndex(filename);
TLongObjectHashMap<TLongDoubleHashMap> correlationMatrix = ItemPairwiseSimilarityUtil.correlatedItems(folder, docIndex);

filename 是您的 docIndex 文件名,folder 是项目相似性文件的文件夹。最后,这只不过是基于项目的推荐。

希望对你有帮助

【讨论】:

  • 如何获得步骤 3 中生成的矩阵的列数,该列数在步骤 4 中需要?
  • 如果您运行第 3 步,它将生成包含列数的输出。我记得输出将是生成的矩阵的行数和列数。
  • 谢谢,我根据这个问题中提到的示例输出通过grepping在我的日志中找到了相关行:stackoverflow.com/q/18429571/2429404
猜你喜欢
  • 1970-01-01
  • 2015-01-16
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 2018-09-28
  • 2015-07-02
  • 1970-01-01
  • 2015-12-26
相关资源
最近更新 更多