BM25算法,通常用来做检索相关性评分。首先对一个查询Query进行分词得qi,对每个搜索结果文档d,计算qi与文档d的相关性得分。最后将所有的qi进行加权求和,从而得到查询Query与文档d的相关性得分。
公式中,Q表示查询Query,qi表示查询被解析得到的分词qi,d表示搜索结果文档d,Wi表示分词qi的权重,R(qi,d)表示分词qi与文档d的相关性得分。定义一个词与文档相关性的权重方法有很多,较常用的有IDF。
其中N表示全部文档数,n(qi)表示包含分词qi的文档数,从公式中可以发现当包含分词qi的文档数越多时,qi的权重越低,即当很多文档都有单词qi时,说明qi比较常用,没有特别代表意义,所以分词qi拿来做相关性判断时重要性比较低。下面是qi与文档d相关性得分R(qi,d)的计算公式。
式子中,k1、k2、b为调节因子,通常根据经验设置为k1=2,b=0.75,fi为qi在d中出现的频率,qfi为qi在查询Query中出现的频率。dl为文档d的长度,avgdl为所有文档的平均长度。在多数情况下qi只在查询中出现一次,qfi=1,所以公式简化为:
从K的公式中发现,b越大文档长度对相关性得分的影响也越大,而文档的长度越长,K越大,则相关性得分越小。所以参数b用来控制文档长度对相关性得分影响的大小。所以当文档较长时,包含分词qi的概率越大,因此同等频率的情况下,长文档与qi的相关性不如短文档与qi的相关性高。综上BM25文档相关性计算公式:
def init(self):
for doc in self.docs:
tmp = {}
for word in doc:
if not word in tmp:
tmp[word] = 0
tmp[word] += 1
self.f.append(tmp)
for k, v in tmp.items():
if k not in self.df:
self.df[k] = 0
self.df[k] += 1
for k, v in self.df.items():
self.idf[k] = math.log(self.D-v+0.5)-math.log(v+0.5)
##计算出每个词的频次来,然后利用之前的公式计算idf
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)))
#利用之前的计算bm25的公式计算。
return score
def simall(self, doc):#该doc(也就是之前提到的搜索预料)与预保存的文档)逐个比较相似情况。返回相似值的列别。
scores = []
for index in range(self.D):
score = self.sim(doc, index)
scores.append(score)
return scores