zoukankan      html  css  js  c++  java
  • 基于熵的方法计算query与docs相似度

    一.简单总结

      其实相似度计算方法也是老生常谈,比如常用的有:

      1.常规方法

        a.编辑距离

        b.Jaccard

        c.余弦距离

        d.曼哈顿距离

        e.欧氏距离

        f.皮尔逊相关系数

      2.语义方法

        a.LSA

        b.Doc2Vec

        c.DSSM

      ......

    二.利用熵计算相似度

      关于什么是熵、相对熵、交叉熵的概念,网上有很多,这里就不总结了。本篇主要关注工程方面,即怎么用代码实现,参考的论文来自《Content-based relevance estimation on the web using inter-document similarities》(2012-CIKM)。

      利用熵计算query与文档相似度并排序的步骤分为召回和重排序,比如先从大规模文档中召回小部分子集再进行重排序。召回部分可以用一些简单的效率高的方法快速确定候选子集,再将这些子集进行重排序。本篇关注如何利用熵重排序相关文档。

      召回后的排序公式如下:

        

      说明:

      (1).H(d)表示文档d的熵

        

        其中=|w|/|d|,分子是词w个数,分母为文档d中的总词数

      (2).文档间的相似度

        

        

        其中表示query的top-k个相关文档;利用交叉熵计算文档间的相似度,这里面的文档去除了query中的词。

        表示语言模型Dirichlet-smoothed,常见的平滑方法如下:

        

        其中Dirichlet 方法:
        a.首先计算最基本的最大的似然估计w|d 单词在单个文档出现的频率(有可能为0,所以就需要平滑,将所有f(w|d1), f(w|d2)....f(w|dn) 的所有频率加总
        b.设定u值,根据实证研究: Dirichlet 方法的u值在100-200之间是最理想 ,但论文中给出的是1000,0为不使用平滑
        c. 计算P(w|C)的概率

        (3).sim(q,d)表示query与doc的相似度,可以使用其它方法计算,也可以使用如(2)中的方法计算

     三.程序

      完整程序https://github.com/jiangnanboy/entropy_sim

      核心程序:

     1 /**
     2      * 结合交叉熵和狄里克雷平滑语言方法计算相关度
     3      * @param queryTerms
     4      * @return
     5      */
     6     private Map<String, Double> queryDocScore(List<String> queryTerms) {
     7         //统计查询中的词频
     8         Map<String, Long> queryTermsCount = queryTerms
     9                 .stream()
    10                 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    11         //查询中的总词频
    12         long queryTermsSize = queryTermsCount
    13                 .values()
    14                 .stream()
    15                 .mapToLong(word -> word)
    16                 .sum();
    17 
    18         //文档集中的词频
    19         Map<String, Long> collectionTermsCount = corpusTerms
    20                 .stream()
    21                 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    22         //文档集中的总词频
    23         long collectionTermsSize = collectionTermsCount
    24                 .values()
    25                 .stream()
    26                 .mapToLong(word -> word)
    27                 .sum();
    28 
    29         Map<String, Double> scoredDocument = new HashMap<>();
    30         documentList.forEach(docTerms -> {
    31             //文档中的词频
    32             Map<String, Long> docTermsCount = docTerms
    33                     .stream()
    34                     .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    35             //文档中的总词频
    36             long docTermsSize = docTermsCount
    37                     .values()
    38                     .stream()
    39                     .mapToLong(word -> word)
    40                     .sum();
    41 
    42             //计算交叉熵(或者相对熵)
    43             OptionalDouble score = queryTerms
    44                     .stream()
    45                     .mapToDouble(queryTerm -> {
    46                         //queryTerm的似然
    47                         double queryCE = (double)queryTermsCount.get(queryTerm) / queryTermsSize;
    48                         //经过Dirichlet smooth的term weight
    49                         double docCE = (1.0 + docTermsCount.getOrDefault(queryTerm, 0L) +
    50                                 this.lambda * (collectionTermsCount.getOrDefault(queryTerm, 0L) / collectionTermsSize)) /
    51                                 (docTermsSize + this.lambda);
    52                         return queryCE * Math.log(1 / docCE);//交叉熵
    53                         //return queryCE * Math.log(queryCE / docCE);//相对熵
    54                     })
    55                     .reduce(Double::sum);
    56             String docID = corpusHashMap.get(docTerms);
    57             scoredDocument.put(docID, Math.exp(-score.getAsDouble()));
    58         });
    59         return scoredDocument;
    60     }
  • 相关阅读:
    JavaScript进行表单提交
    《构建之法》读书笔记2
    一个简单的session传值学习
    javascript相关正则收集
    LINQ中join语法大探究(多表关联),也有不少疑问
    c#排序算法详细探究
    js获得文本框中光标的位置
    linq to sql基本的操作(读,添加,删除,更新)
    不用保存直接读取文件内容
    终于搞明白ajax拉
  • 原文地址:https://www.cnblogs.com/little-horse/p/11253030.html
Copyright © 2011-2022 走看看