BM25S:Python打造超越RANK-BM25的实现
在信息检索领域,BM25是一种广泛应用的排名函数,其核心思想是根据词频、文档长度和文档在整个集合中的重要性来评估文档与查询的相关性。然而,传统的BM25在处理某些特定的检索场景时可能存在局限性,因此开发了BM25S模型。BM25S对BM25进行了扩展,旨在提高检索效果和文档排序准确性。本文将介绍BM25S的基本原理,并给出相应的Python实现代码示例。
BM25的基本原理
BM25模型基于概率检索理论,通过以下公式来计算文档与查询的相关性得分:
[ \text{BM25}(d, q) = \sum_{t \in q} \text{idf}(t) \times \frac{f(t, d) \times (k_1 + 1)}{f(t, d) + k_1 \times (1 - b + b \times \frac{|d|}{\text{avgdl}})} ]
其中: - (d) 是文档,(q) 是查询。 - (f(t, d)) 是词t在文档d中的频率。 - (|d|) 是文档d的长度(词数)。 - (\text{avgdl}) 是文档集合中所有文档的平均长度。 - (k_1) 和 (b) 是调节参数,通常设定为 (k_1 \in [1.2, 2.0]) 和 (b \in [0.5, 0.8])。
BM25S的改进
BM25S在BM25的基础上增加了对短文档和长文档的不同处理方式。BM25S考虑了目标文档的整体语义信息,通过引入“内容深度”和“相关性加权”的思想来改善相关性评分,使得模型能够更好地适应多种不同的检索场景。
Python实现示例
以下是BM25及BM25S的Python实现示例,我们先实现BM25:
import math
from collections import Counter
class BM25:
def __init__(self, documents, k1=1.5, b=0.75):
self.documents = documents
self.k1 = k1
self.b = b
self.avgdl = sum(len(doc) for doc in documents) / len(documents)
self.doc_freqs = []
self.idf = {}
# 计算文档频率
for document in documents:
counter = Counter(document)
self.doc_freqs.append(counter)
self._compute_idf()
def _compute_idf(self):
df = Counter()
for doc in self.doc_freqs:
for word in doc.keys():
df[word] += 1
N = len(self.documents)
for word, freq in df.items():
self.idf[word] = math.log((N - freq + 0.5) / (freq + 0.5) + 1)
def score(self, document, query):
score = 0.0
doc_len = len(document)
counter = Counter(document)
for term in query:
if term in counter:
tf = counter[term]
score += self.idf[term] * (tf * (self.k1 + 1)) / (tf + self.k1 * (1 - self.b + self.b * (doc_len / self.avgdl)))
return score
# 示例
documents = [['this', 'is', 'a', 'sample', 'document'], ['this', 'document', 'is', 'another', 'example']]
bm25 = BM25(documents)
query = ['this', 'document']
for idx, doc in enumerate(documents):
print(f'Document {idx} score: {bm25.score(doc, query)}')
接下来实现BM25S:
class BM25S(BM25):
def __init__(self, documents, k1=1.5, b=0.75):
super().__init__(documents, k1, b)
def score(self, document, query):
score = super().score(document, query)
# 加入BM25S的扩展调整
content_depth = self._compute_content_depth(document, query)
return score * content_depth
def _compute_content_depth(self, document, query):
# 一个简单的内容深度计算示例
relevance = len(set(document) & set(query)) / len(query)
return 1 + relevance
# 示例
bm25s = BM25S(documents)
for idx, doc in enumerate(documents):
print(f'Document {idx} BM25S score: {bm25s.score(doc, query)}')
总结
BM25S通过引入新颖的内容深度计算方式,提升了文档与查询的匹配度,为信息检索提供了更为精准的排名结果。以上代码实现展示了BM25和BM25S在Python中的基本应用。在实际应用中,可以进一步根据不同的业务需求调整参数和扩展模型,以达到最优的检索效果。