史上最小白之BM25详解与实现

原理

BM25算法是一种计算句子与文档相关性的算法,它的原理十分简单:将输入的句子sentence进行分词,然后分别计算句子中每个词word与文档doc的相关度,然后进行加权求和。得到句子与文档的相关度评分。评分公式如下:
S c o r e ( Q , d ) = ∑ i n W i R ( q i , d ) Score(Q,d) = \sum_i^nW_iR(q_i,d) Score(Q,d)=i∑n​Wi​R(qi​,d)
上面公式中Wi表示权重,也就是idf值。R(qi,d)是word q与文档d的相关性得分。

IDF

idf 也就是逆文档频率,计算公式如下:
I D F ( q i ) = l o g ( N − n ( q i ) + 0.5 n ( q i ) + 0.5 ) IDF(q_i)=log(\frac{N-n(q_i)+0.5}{n(q_i)+0.5}) IDF(qi​)=log(n(qi​)+0.5N−n(qi​)+0.5​)
N表示所有文档D中的文档d的数目,也就是总共有多少篇文档来与sentence计算相关性得分,n(qi)为文档d中包含了词qi的数目。从idf的公式我们可以看出,n(qi)越大则分母越大,分子越小,也就是相应地IDF值越小。这是因为加入一个词在多篇文档中出现,那么一定程度上能说明这个词应该是一个使用比较普遍的词,在任何sentence中他都存在,不能体现sentence这一句话的特殊性,因此赋予它更小的idf值。

代入到BM25算法中idf值作为权重,也就是说明一个词word在越多的文档d中出现,那么他与文档d计算的相关性得分就应该赋予更小的权重。

R相关性得分

先来看看R(qi,d)相关性得分的一般性公式:
R ( q i , d ) = f i ⋅ ( k 1 + 1 ) f i + K ⋅ q f i ⋅ ( k 2 + 1 ) q f i + k 2 R(q_i,d)=\frac{f_i\cdot(k_1+1)}{f_i+K}\cdot\frac{qf_i\cdot(k_2+1)}{qf_i+k_2} R(qi​,d)=fi​+Kfi​⋅(k1​+1)​⋅qfi​+k2​qfi​⋅(k2​+1)​

K = k 1 ⋅ ( 1 − b + b ⋅ d l a v g d l ) K=k1\cdot(1-b+b\cdot\frac{dl}{avgdl}) K=k1⋅(1−b+b⋅avgdldl​)

上述公式中,k1,k2,b是调节因子,一般根据经验来自己设置,通常k1=2,b=0.75;fi表示qi在文档d中出现的频率,qfi为qi在输入句子sentence中的频率。dl为文档d的长度,avgdl为文档D中所有文档的平均长度。

又因为在绝大部分情况下,qi在sentence中只出现一次,即所有的qi的qfi基本上都是一样地,因此可以将k2取0,然后将上述公式进行简化。
KaTeX parse error: Undefined control sequence: \ at position 40: …(k_1+1)}{f_i+K}\̲ ̲
接下来就是需要计算K,便能计算出相关性得分R了。

从K的公式可以看出,参数b是调整文档长度对于相关性的影响。可以看出b越大,文档长度对相关性得分的影响越大,反之越小。而文档d的相对长度越长,K越大,也就是R的分母越大,R相关性得分也就越小。这里可以理解成,当文档较长时,包含的词语也就越多,那么相应地包含有qi这个词的可能性也就越大,但是虽然可能性要大一点,要是当qi的频率fi同等的情况下,长文档与qi的相关性就应该比短文档与qi的相关性弱。

最后可以将BM25算法的相关性得分的公式进行汇总:
S c o r e ( Q , d ) = ∑ i n I D F ( q i ) ⋅ f i ⋅ ( k 1 + 1 ) f i + k 1 ⋅ ( 1 − b + b ⋅ d l a v g d l ) Score(Q,d) = \sum_i^nIDF(q_i)\cdot\frac{f_i\cdot(k_1+1)}{f_i+k_1\cdot(1-b+b\cdot\frac{dl}{avgdl})} Score(Q,d)=i∑n​IDF(qi​)⋅fi​+k1​⋅(1−b+b⋅avgdldl​)fi​⋅(k1​+1)​

代码实现:

import math
import jieba
import numpy as np
import logging
import pandas as pd
from collections import Counter
jieba.setLogLevel(logging.INFO)# 测试文本
text = '''
自然语言处理是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。
自然语言处理是一门融语言学、计算机科学、数学于一体的科学。因此,这一领域的研究将涉及自然语言,即人们日常使用的语言,所以它与语言学的研究有着密切的联系,但又有重要的区别。
自然语言处理并不是一般地研究自然语言,而在于研制能有效地实现自然语言通信的计算机系统,特别是其中的软件系统。因而它是计算机科学的一部分。
'''class BM25(object):def __init__(self,docs):self.docs = docs   # 传入的docs要求是已经分好词的list self.doc_num = len(docs) # 文档数self.vocab = set([word for doc in self.docs for word in doc]) # 文档中所包含的所有词语self.avgdl = sum([len(doc) + 0.0 for doc in docs]) / self.doc_num # 所有文档的平均长度self.k1 = 1.5self.b = 0.75def idf(self,word):if word not in self.vocab:word_idf = 0else:qn = {}for doc in self.docs:if word in doc:if word in qn:qn[word] += 1else:qn[word] = 1else:continueword_idf = np.log((self.doc_num - qn[word] + 0.5) / (qn[word] + 0.5))return word_idfdef score(self,word):score_list = []for index,doc in enumerate(self.docs):word_count = Counter(doc)if word in word_count.keys():f = (word_count[word]+0.0) / len(doc)else:f = 0.0r_score = (f*(self.k1+1)) / (f+self.k1*(1-self.b+self.b*len(doc)/self.avgdl))score_list.append(self.idf(word) * r_score)return score_list def score_all(self,sequence):sum_score = []for word in sequence:sum_score.append(self.score(word))sim = np.sum(sum_score,axis=0) return sim
if __name__ == "__main__":# 获取停用词stopwords = open('./drive/My Drive/Colab/stopwords/哈工大停用词表.txt').read().split('\n')doc_list = [doc for doc in text.split('\n') if doc != '']docs = []for sentence in doc_list:sentence_words = jieba.lcut(sentence)tokens = []for word in sentence_words:if word in stopwords:continueelse:tokens.append(word)docs.append(tokens)bm = BM25(docs)score = bm.score_all(['自然语言', '计算机科学', '领域', '人工智能', '领域'])print(score)

结果:

可以看到我们的输入与第二句的相关性得分最高。

结语:

好了,这期的BM25算法的介绍就到这里啦,不知道说得算不算清晰,要是还有不懂的或者发现有遗漏和错误的地方欢迎指正。
生命不息,学习不止,一起加油吧!!!奥利给!!!

参考:

https://www.jianshu.com/p/1e498888f505

史上最小白之BM25详解与实现相关推荐

  1. 史上最小白之Transformer详解

    1.前言 博客分为上下两篇,您现在阅读的是下篇史上最小白之Transformer详解,在阅读该篇博客之前最好你能够先明白Encoder-Decoder,Attention机制,self-Attenti ...

  2. 史上最小白之Bert详解

    1.前言 关于BERT,张俊林博士有一篇特别好的文章:从Word Embedding到Bert模型-自然语言处理中的预训练技术发展史 非常透彻地讲解了Bert是怎么样从NNLM->Word2Ve ...

  3. 史上最小白之RNN详解

    1.前言 网上目前已经有诸多优秀的RNN相关博客,但是我写博客的出发点主要是为了加深和巩固自己的理解,所以还是决定自己再进行一下总结和描述,如有不正确的地方欢迎指正~ 2.区分RNN 循环神经网络(R ...

  4. 史上最小白之Attention详解

    1.前言 在自然语言处理领域,近几年最火的是什么?是BERT!谷歌团队2018提出的用于生成词向量的BERT算法在NLP的11项任务中取得了非常出色的效果,堪称2018年深度学习领域最振奋人心的消息. ...

  5. 史上最简单MySQL教程详解(进阶篇)之存储过程(一)

    史上最简单MySQL教程详解(进阶篇)之存储过程(一) 史上最简单MySQL教程详解(进阶篇)之存储过程(一) 什么是存储过程 存储过程的作用 如何使用存储过程 创建存储过程 DELIMITER改变分 ...

  6. 史上最简单MySQL教程详解(进阶篇)之存储引擎介绍及默认引擎设置

    什么是存储引擎? MySQL存储引擎种类 MyISAM 引擎 InnoDB引擎 存储引擎操作 查看存储引擎 存储引擎的变更 修改默认引擎 什么是存储引擎? 与其他数据库例如Oracle 和SQL Se ...

  7. 史上最简单MySQL教程详解(进阶篇)之索引及失效场合总结

    史上最简单MySQL教程详解(进阶篇)之索引及其失效场合总结 什么是索引及其作用 索引的种类 各存储引擎对于索引的支持 简单介绍索引的实现 索引的设置与分析 普通索引 唯一索引(Unique Inde ...

  8. 史上最简单MySQL教程详解(进阶篇)之视图

    史上最简单MySQL教程详解(进阶篇)之视图 为什么要用视图 视图的本质 视图的作用 如何使用视图 创建视图 修改视图 删除视图 查看视图 使用视图检索 变更视图数据 WITH CHECK OPTIO ...

  9. 史上最全 JVM 大全详解、java 程序员细节到极致的一次,魔鬼

    前言 作为 Java 的从业者,在找工作的时候,一定会被问及关于 JVM 相关的知识. JVM 知识的掌握程度,在很多面试官眼里是候选人技术深度的一个重要评判标准.而大多数人可能没有对 JVM 的实际 ...

最新文章

  1. XState Viz 可视化和调试状态机
  2. 【ujson】pip安装ujson报错: error:Microsoft Visual C++ 14.0 is required
  3. 一款打包免签分发平台源码+搭建说明
  4. Hadoop学习总结(1)——大数据以及Hadoop相关概念介绍
  5. Swift 5新特性详解:ABI 稳定终于来了!
  6. 前端与移动开发之vue-day3(4)
  7. Javascript iframe交互并兼容各种浏览器的解决方案
  8. 为什么摩根大通「发币」标志着企业区块链应用元年?
  9. 通达信资金净流入公式_通达信资金净流量指标公式
  10. vissim免修改时间工具_视频剪辑工具premiere最基础使用教程
  11. 迅捷新版PDF转换器
  12. axis调用webservice
  13. 内网网段范围_局域网IP段有哪些 - 卡饭网
  14. 人工智能 感情 自我意识
  15. 基于Vue的数据埋点统计
  16. 利用ptython中的tutle画了一个表情包——2020冲冲冲!!
  17. ppt制作的一些要点
  18. 鼠标悬停出现遮罩或图片放大效果
  19. PHP后端连接数据库插入数据
  20. 安卓Apk安装出错:更新包与已安装应用的签名不一致,但在应用管理中却找不到这个已经卸载的应用

热门文章

  1. 东京商城注册页面使用的正则表达式......
  2. 信息技术重返MBA课程
  3. 多元函数条件极值的求法 拉格朗日乘数法
  4. FreeFileSync命令用法
  5. GPL和MIT开源协议
  6. shell命令查阅端口信息_Linux服务器管理Shell经典命令
  7. ENSP华为模拟器:基础命令及简写
  8. shell——正则表达式
  9. openswan协商流程之(四):main_inI2_outR2()
  10. CESM模式及其各个分量模式介绍