BM25算法解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BM25算法解析相关的知识,希望对你有一定的参考价值。
参考技术A参考文档: http://luokr.com/p/7
ElasticSearch相关度是根据打分机制来计算的。对于每一条搜索结果都会计算出相应的得分,分数越高,代表相关度越高。BM25算法是ElstaticSearch默认的打分算法。
BM25算法通常用来作为搜索相关性评分:对查询经进行语素解析,生成语素气;然后,对于每个搜索结果d,计算每个语素气与d的相关性得分,最后,将气相对于d的相关性得分进行加权求和,从而得到查询与d的相关性得分。
BM25:
首先解析公式前半段:
科普:IDF又叫做逆向文档频率,意思就是 对于给定的文档集合(意思就是公文索引库),包含该关键字的文档越多,该关键字的权重越低(对于整个索引库来说,该关键字出现的次数越多,说明此关键字的参考价值越低);
其中,Q表示查询,补气(就是把一句搜索的话分成若干个关键词)标识Q解析之后的一个语素(对中文而言,我们可以把对查询的分词作为语素分析,每个词看成语素补气);d标识一个搜索结果文档(就相当与一条搜索出来的公文),无线表示语素气的权重。
IDF(逆向文档频率)计算公式如下:
其中,N为索引中的全部文档数,N(QI)为包含了气(也就是关键字)的文档数。
再来看关键词与文档d的相关性得分R(气,d),也就是BM25算法的后半部分
其中,K1为调节因子,b=0.75,avgdl为所有文档的平均长度,dl为文档d的长度,从K的定义中可以看出,参数b的作用是调整文档长度对相关性影响的大小,b越大,文档长度的对相关性得分影响越大,而文档相对长度越长,K值将越大,则相关性的分会越小。
总结:
影响ElasticSearch得分因素:
1.词频,搜索关键词在文档d中出现的次数成正比
2.逆向文档频率,搜索关键词在索引库中出现的次数成反比
3.文档d的长度成反比
4.搜索语句在文档d中的匹配度成正比
BM25算法语义相似度计算
原理
BM25算法,通常用来作搜索相关性平分。一句话概况其主要思想:对Query进行语素解析,生成语素qi;然后,对于每个搜索结果D,计算每个语素qi与D的相关性得分,最后,将qi相对于D的相关性得分进行加权求和,从而得到Query与D的相关性得分。
BM25算法的一般性公式如下:
其中,Q表示Query,qi表示Q解析之后的一个语素(对中文而言,我们可以把对Query的分词作为语素分析,每个词看成语素qi。);d表示一个搜索结果文档;Wi表示语素qi的权重;R(qi,d)表示语素qi与文档d的相关性得分。
下面我们来看如何定义Wi。判断一个词与一个文档的相关性的权重,方法有多种,较常用的是IDF。这里以IDF为例,公式如下:
其中,N为索引中的全部文档数,n(qi)为包含了qi的文档数。
根据IDF的定义可以看出,对于给定的文档集合,包含了qi的文档数越多,qi的权重则越低。也就是说,当很多文档都包含了qi时,qi的区分度就不高,因此使用qi来判断相关性时的重要度就较低。
我们再来看语素qi与文档d的相关性得分R(qi,d)。首先来看BM25中相关性得分的一般形式:
其中,k1,k2,b为调节因子,通常根据经验设置,一般k1=2,b=0.75;fi为qi在d中的出现频率,qfi为qi在Query中的出现频率。dl为文档d的长度,avgdl为所有文档的平均长度。由于绝大部分情况下,qi在Query中只会出现一次,即qfi=1,因此公式可以简化为:
从K的定义中可以看到,参数b的作用是调整文档长度对相关性影响的大小。b越大,文档长度的对相关性得分的影响越大,反之越小。而文档的相对长度越长,K值将越大,则相关性得分会越小。这可以理解为,当文档较长时,包含qi的机会越大,因此,同等fi的情况下,长文档与qi的相关性应该比短文档与qi的相关性弱。
综上,BM25算法的相关性得分公式可总结为:
从BM25的公式可以看到,通过使用不同的语素分析方法、语素权重判定方法,以及语素与文档的相关性判定方法,我们可以衍生出不同的搜索相关性得分计算方法,这就为我们设计算法提供了较大的灵活性。
参考来源:https://www.jianshu.com/p/1e498888f505
CODING
import math import jieba # from utils import utils STOPWORDS = open(‘resources/stopwords.txt‘, ‘r‘, encoding=‘utf8‘).readlines() STOPWORDS = {each.strip():1 for each in STOPWORDS} # 测试文本 text = ‘‘‘ 自然语言处理是计算机科学领域与人工智能领域中的一个重要方向。 它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。 自然语言处理是一门融语言学、计算机科学、数学于一体的科学。 因此,这一领域的研究将涉及自然语言,即人们日常使用的语言, 所以它与语言学的研究有着密切的联系,但又有重要的区别。 自然语言处理并不是一般地研究自然语言, 而在于研制能有效地实现自然语言通信的计算机系统, 特别是其中的软件系统。因而它是计算机科学的一部分。 ‘‘‘ class BM25(object): def __init__(self, docs): self.D = len(docs) self.avgdl = sum([len(doc)+0.0 for doc in docs]) / self.D self.docs = docs self.f = [] # 列表的每一个元素是一个dict,dict存储着一个文档中每个词的出现次数 self.df = {} # 存储每个词及出现了该词的文档数量 self.idf = {} # 存储每个词的idf值 self.k1 = 1.5 self.b = 0.75 self.init() def init(self): for doc in self.docs: tmp = {} for word in doc: tmp[word] = tmp.get(word, 0) + 1 # 存储每个文档中每个词的出现次数 self.f.append(tmp) for k in tmp.keys(): self.df[k] = self.df.get(k, 0) + 1 for k, v in self.df.items(): self.idf[k] = math.log(self.D-v+0.5)-math.log(v+0.5) def sim(self, doc, index): score = 0 for word in doc: if word not in self.f[index]: continue d = len(self.docs[index]) score += (self.idf[word]*self.f[index][word]*(self.k1+1) / (self.f[index][word]+self.k1*(1-self.b+self.b*d / self.avgdl))) return score def simall(self, doc): scores = [] for index in range(self.D): score = self.sim(doc, index) scores.append(score) return scores if __name__ == ‘__main__‘: # sents = utils.get_sentences(text) sents = [each.strip() for each in text.split(‘。‘)] doc = [] for sent in sents: words = list(jieba.cut(sent)) words = [each for each in words if each not in STOPWORDS] doc.append(words) print(doc) s = BM25(doc) print(‘freq of sentences:{}‘.format(s.f)) print(‘idf of sentences:{}‘.format(s.idf)) # print(s.simall([‘自然语言‘, ‘计算机科学‘, ‘领域‘, ‘人工智能‘, ‘领域‘])) print(s.simall([‘自然语言‘, ‘计算机科学‘, ‘科学‘]))
以上是关于BM25算法解析的主要内容,如果未能解决你的问题,请参考以下文章