tang-hi

Don't Panic

文本相关性

Posted at # Full Text Search

文本相关性是信息检索和自然语言处理中的一个核心问题。在文本相关性中,我们希望能够量化文本之间的相似程度或相关程度,以便有效地处理和组织文本数据。例如,在搜索引擎中,我们希望通过用户的查询来找到与查询相关的最相关的文档或网页。在文档分类和聚类中,我们希望将相似的文档放在一起,以便更好地管理和分析它们。在文本匹配和相似性匹配中,我们希望找到两个文本之间的相似度,以便评估它们之间的关系。

这篇博客会介绍 TF-IDF 以及 BM25

tf-idf

tf-idf(Term Frequency-Inverse Document Frequency)是一种用于评估文档中单词重要性的统计方法,广泛应用于信息检索、自然语言处理等领域。

他的整体公式如下

tf-idf(t,d,D)=tf(t,d)idf(t,D)\text{tf-idf}(t,d,D) = \text{tf}(t,d) \cdot \text{idf}(t,D)

其中,tt 是指某个单词(term),dd 是指某个文档(document),DD 是指整个文档集合。tf 表示单词在文档中的频率(term frequency)。idf 表示单词在整个文档集合中的逆文档频率(inverse document frequency)。

它们的计算公式如下:

tf(t,d)=ft,dtdft,d\text{tf}(t,d) = \frac{f_{t,d}}{\sum_{t' \in d} f_{t',d}}

其中,ft,df_{t,d} 是指单词 tt 在文档 dd 中出现的次数。

idf(t,D)=logNdD:td\text{idf}(t,D) = \log{\frac{N}{|{d \in D : t \in d}|}}

其中,NN 是指整个文档集合中文档的总数,dD:td|{d \in D : t \in d}| 是指包含单词 tt 的文档数。

tf-idf考虑了一个单词在文档中的频率以及在整个文档集合中的频率,从而确定它在文档中的重要性。一个单词在某个文档中出现的次数越多,其重要性就越高(即tf越高),但是如果它在整个文集中出现的次数也很多,那么它的重要性就会降低(即idf越低)

通过例子深入理解tf-idf

假设我们有一个包含以下 4 个文档的文档集合:

Doc 1: the cat in the hat

Doc 2: the rat in the hat

Doc 3: the cat and the rat

Doc 4: the cat sat on the hat

现在,我们想要计算单词 “cat” 在文档集合中的 tf-idf 值。首先,我们需要计算单词 “cat” 在每个文档中的 tf 值。计算公式如下:

tf(t,d)=ft,dtdft,d\text{tf}(t,d) = \frac{f_{t,d}}{\sum_{t' \in d} f_{t',d}}

其中,ft,df_{t,d} 表示单词 tt 在文档 dd 中出现的次数,tdft,d\sum_{t' \in d} f_{t',d} 表示文档 dd 中所有单词的出现次数之和。因此,单词 “cat” 在每个文档中的 tf 值为:

tf(cat, Doc 1) = 1/5 = 0.2
tf(cat, Doc 2) = 0/5 = 0
tf(cat, Doc 3) = 1/6 = 0.1667
tf(cat, Doc 4) = 1/7 = 0.1429

接下来,我们需要计算单词 “cat” 在整个文档集合中的 idf 值。计算公式如下:

idf(t,D)=logNdD:td\text{idf}(t,D) = \log{\frac{N}{|{d \in D : t \in d}|}}

其中,NN 表示文档集合中文档的总数,dD:td|{d \in D : t \in d}| 表示包含单词 tt 的文档数。因此,单词 “cat” 在整个文档集合中的 idf 值为:

idf(cat,D)=log430.2877\text{idf}(cat, D) = \log{\frac{4}{3}} \approx 0.2877

最后,我们可以计算单词 “cat” 在每个文档中的 tf-idf 值,计算公式如下:

tf-idf(t,d,D)=tf(t,d)idf(t,D)\text{tf-idf}(t,d,D) = \text{tf}(t,d) \cdot \text{idf}(t,D)

因此,单词 “cat” 在每个文档中的 tf-idf 值为:

tf-idf(cat, Doc 1, D) = 0.2 * 0.2877 = 0.0575
tf-idf(cat, Doc 2, D) = 0 * 0.2877 = 0
tf-idf(cat, Doc 3, D) = 0.1667 * 0.2877 = 0.0481
tf-idf(cat, Doc 4, D) = 0.1429 * 0.2877 = 0.0412

这样,我们就计算出了单词 “cat” 在每个文档中的 tf-idf 值。可以看到,单词 “cat” 在 Doc 1 和 Doc 3中的 tf-idf 值比较高,因为它们在文档中出现得比较少,并且在文档集合中出现的文档数也比较少,表明它们在文档集合中比较重要。

BM25

tf-idf 相似,BM25 也是基于词频的算法,但与 tf-idf 不同的是,BM25 引入了文档长度的因素,同时对词频的权重进行了调整。BM25 的全称是 Best Matching 25,它计算的是一个查询(query)与一个文档(document)之间的相似度得分。BM25 基于以下三个因素来计算文档的得分:

  1. 查询项(query term)在文档中的出现次数

  2. 文档的长度(即包含的单词数)

  3. 查询项的文档频率(即包含查询项的文档数量)

BM25 的公式如下:

BM25(q,d)=i=1qidf(qi)f(qi,d)(k1+1)f(qi,d)+k1(1b+bdavgdl)\text{BM25}(q, d) = \sum_{i=1}^{|q|} \text{idf}(q_i) \cdot \frac{f(q_i, d) \cdot (k_1 + 1)}{f(q_i, d) + k_1 \cdot (1 - b + b \cdot \frac{|d|}{\text{avgdl}})}

其中,

  • qq 是查询项
  • dd 是文档
  • q|q| 是查询项的数量
  • qiq_i 是第 ii 个查询项
  • idf(qi)\text{idf}(q_i) 是查询项 qiq_i 的逆文档频率(inverse document frequency),定义为 idf(qi)=logNn(qi)+0.5n(qi)+0.5\text{idf}(q_i) = \log{\frac{N - n(q_i) + 0.5}{n(q_i) + 0.5}}
    • NN 是文档集合中的文档数
    • n(qi)n(q_i) 是包含查询项 qiq_i 的文档数
  • f(qi,d)f(q_i, d) 是查询项 qiq_i 在文档 dd 中出现的次数
  • d|d| 是文档 dd 中的单词数
  • avgdl\text{avgdl} 是文档集合中所有文档的平均长度
  • k1k_1bb 是常数,通常取 k1=1.2k_1 = 1.2b=0.75b = 0.75

BM25 中,查询项的权重由两个因素决定:逆文档频率(idf)和词频(tf)。与 tf-idf 相似,idf 用于衡量一个查询项的重要程度,tf 用于衡量查询项在文档中的出现频率。不同之处在于,BM25 引入了文档长度和查询项的文档频率来对词频进行加权。

具体来说,当文档长度很小时,BM25 对词频进行较大的加权,这可以帮助我们区分出现次数很少但重要的查询项;而当文档长度很大时,BM25 对词频进行较小的加权,以避免受过多出现的常见查询项的影响。此外,BM25 的常数参数 k1k_1bb 也可以根据实际情况进行调整,以获得更好的结果。

计算 BM25 的例子:

假设我们有一个文档集合,其中包含三个文档 D1,D2,D3D_1, D_2, D_3,它们的长度分别为 D1=100,D2=200,D3=300|D_1|=100, |D_2|=200, |D_3|=300。我们还有一个查询项 qq,其中包含两个单词 q1q_1q2q_2。假设 q1q_1D1D_1 中出现了 2 次,在 D2D_2 中出现了 5 次,在 D3D_3 中出现了 10 次;q2q_2D1D_1 中出现了 3 次,在 D2D_2 中出现了 1 次,在 D3D_3 中没有出现。

我们需要计算每个文档与查询项 qqBM25 得分。为了简化,我们假设 k1=1.2k_1 = 1.2b=0.75b = 0.75

首先,我们需要计算每个查询项的逆文档频率 idf(qi)\text{idf}(q_i)。根据公式,我们可以得到:

idf(q1)=log32+0.52+0.50.29\text{idf}(q_1) = \log{\frac{3 - 2 + 0.5}{2 + 0.5}} \approx 0.29

idf(q2)=log30+0.50+0.51.79\text{idf}(q_2) = \log{\frac{3 - 0 + 0.5}{0 + 0.5}} \approx 1.79

接下来,我们需要计算每个文档与查询项 qq 的 BM25 得分。根据公式,我们可以得到:

BM25(q,D1)=idf(q1)2(1.2+1)2+1.2(10.75+0.75100200)+idf(q2)3(1.2+1)3+1.2(10.75+0.75100200)0.78\text{BM25}(q, D_1) = \text{idf}(q_1) \cdot \frac{2 \cdot (1.2 + 1)}{2 + 1.2 \cdot (1 - 0.75 + 0.75 \cdot \frac{100}{200})} + \text{idf}(q_2) \cdot \frac{3 \cdot (1.2 + 1)}{3 + 1.2 \cdot (1 - 0.75 + 0.75 \cdot \frac{100}{200})} \approx 0.78 BM25(q,D2)=idf(q1)5(1.2+1)5+1.2(10.75+0.75200200)+idf(q2)1(1.2+1)1+1.2(10.75+0.75200200)0.63\text{BM25}(q, D_2) = \text{idf}(q_1) \cdot \frac{5 \cdot (1.2 + 1)}{5 + 1.2 \cdot (1 - 0.75 + 0.75 \cdot \frac{200}{200})} + \text{idf}(q_2) \cdot \frac{1 \cdot (1.2 + 1)}{1 + 1.2 \cdot (1 - 0.75 + 0.75 \cdot \frac{200}{200})} \approx 0.63 BM25(q,D3)=idf(q1)10(1.2+1)10+1.2(10.75+0.75300200)+idf(q2)0(1.2+1)0+1.2(10.75+0.75300200)0.69\text{BM25}(q, D_3) = \text{idf}(q_1) \cdot \frac{10 \cdot (1.2 + 1)}{10 + 1.2 \cdot (1 - 0.75 + 0.75 \cdot \frac{300}{200})} + \text{idf}(q_2) \cdot \frac{0 \cdot (1.2 + 1)}{0 + 1.2 \cdot (1 - 0.75 + 0.75 \cdot \frac{300}{200})} \approx 0.69

因此,我们可以得到三个文档与查询项 qqBM25 得分分别为 0.78、0.63 和 0.69。

这个例子说明了,虽然 q1q_1D3D_3 中出现的次数最多,但是由于 D3D_3 的长度较长,而且 q2q_2 没有在 D3D_3 中出现,因此 D1D_1 的得分最高。这也说明了 BM25 算法的优点之一,即克服了 tf-idf 算法中常见查询项对结果的影响。

BM25的公式进一步解读

  • BM25中的idf公式与原版的idf公式不一致

    传统的 idf 公式是 logNdf\log\frac{N}{df},其中 NN 是文档集合中文档的总数,dfdf 是包含查询项 tt 的文档数。而 BM25 中使用的 idf 公式是 logNdf+0.5df+0.5\log\frac{N-df+0.5}{df+0.5}。这个公式与传统的 idf 公式相比,主要做了两个改动:

    1. 加入了平滑因子:在传统的 idf 公式中,当某个查询项在文档集合中未出现时,其 idf 值会变成负无穷。为了避免这种情况,BM25 中的 idf 公式加入了平滑因子 0.5。

    2. 减少 idf 的影响:在传统的 idf 公式中,当某个查询项在很少的文档中出现时,其 idf 值会很大,对结果产生过大的影响。BM25 中的 idf 公式通过减少 idf 的影响,使得查询项在出现文档数较少时,不会对结果产生过大的影响。但是当文档出现的数量超过一半时,计算出的idf值为负数,Lucene中为了解决这个问题,更改了idf公式为log1+Ndf+0.5df+0.5\log1+\frac{N-df+0.5}{df+0.5},从而防止了负数的产生。

  • BM25中的k是如何影响计算出的结果 kk 的值控制了词频对得分的影响程度,可以看作是一个词频的归一化因子。

    kk 的值较小时,词频的影响就相对较小,得分的变化范围也相对较小;当 kk 的值较大时,词频的影响就相对较大,得分的变化范围也相对较大。当 kk 的值等于 00 时,相当于将文档中所有词项的词频都视为 11,此时得分只与文档与查询语句的匹配程度有关。同时,因为有kk的存在,即使词频特别大,也不会对最终计算的结果有大的影响。即当词频达到一定程度,计算出的BM25的值并不会线性提升。

  • BM25中的b是如何影响计算出的结果 在 BM25 中,参数 bb 用来平衡文档长度对得分的影响。它控制了文档长度对得分的影响程度,可以看作是一个文档长度的归一化因子。bb 的取值会影响文档中的词项权重 wiw_i 的大小,这里的 wiw_i 是指包含词项 ii 的文档的 ii 的权重。当 bb 越大时,表示文档长度对词项权重的影响越大,这意味着文档中的词项权重 wiw_i 会相应地趋于缩小;反之,当 bb 越小时,表示文档长度对词项权重的影响越小,这意味着文档中的词项权重 wiw_i 会相应地趋于扩大。

  • BM25中的文档长度如何影响计算出的结果

    一篇文档如果所含的单词越少,那么 davgdl\frac{|d|}{\text{avgdl}} 越小,从而导致最终的BM25越大,因此文档字数越少,相关性越高.

  • idf为什么要用对数计算? 在计算文档中每个词项的逆文档频率时,使用对数函数的目的是将idf值的范围压缩到一个较小的区间内。由于文档的大小通常会很大,因此一个词项可能会出现几千甚至几十万次,这样计算得到的idf值就会非常大。使用对数函数可以将这些大数值压缩到一个较小的区间内,便于计算和处理。 此外,对数函数还能够使得低频词项的idf值更加突出。如果不使用对数函数,那么在某些情况下,一些低频词项的idf值可能会非常小,甚至可能会被忽略。而使用对数函数后,这些低频词项的idf值就会被放大,使得它们在检索时能够更好地区分文档的相关性。

BM25F

BM25FBM25算法的一种变体,它在BM25的基础上增加了对多字段的支持。在BM25F中,每个文档可以包含多个字段(例如标题、正文、标签等),每个字段都有一个权重。BM25F通过将每个字段的得分相加来计算文档的相关性得分。BM25F的公式如下:

score(D,Q)=i=1nweight(qi)IDF(qi)f(qi,D)(ki+1)f(qi,D)+ki(1bi+biDavgdli)score(D,Q) = \sum_{i=1}^{n}weight(q_i)\cdot IDF(q_i)\cdot \frac{f(q_i,D)\cdot (k_i + 1)}{f(q_i,D) + k_i\cdot (1 - b_i + b_i \cdot \frac{|D|}{avgdl_i})}

其中,DD表示文档,QQ表示查询,nn表示查询中的词项数,qiq_i表示查询中的第ii个词项,weight(qi)weight(q_i)表示第ii个词项的权重,IDF(qi)IDF(q_i)表示第ii个词项的逆文档频率,f(qi,D)f(q_i,D)表示文档DD中第ii个词项的出现频率,kik_ibib_i分别表示第ii个词项的参数kkbbD|D|表示文档DD的长度,avgdliavgdl_i表示包含第ii个字段的所有文档的平均长度。

BM25F中,每个词项的权重由其所在的字段的权重和全局权重两部分组成。全局权重表示该词项在整个文集中的重要性,字段权重则表示该词项在当前字段中的重要性。词项的权重可以通过以下公式计算:

weight(qi)=weightfield(qi)weightglobal(qi)weight(q_i) = weight_{field}(q_i)\cdot weight_{global}(q_i)

其中,weightfield(qi)weight_{field}(q_i)表示第ii个词项在当前字段中的权重,weightglobal(qi)weight_{global}(q_i)表示第ii个词项在全局文档集中的权重。

BM25F的优点是能够有效地处理多字段查询,可以更好地匹配查询和文档中不同字段的相关性。它可以通过调整字段的权重来对不同字段的重要性进行调整,从而提高搜索结果的准确性。

总结

  1. tf-idf 词频越高,词频在整个文档集中越稀少,值越高

  2. BM25 词频在整个文档集中越稀少,词频越高,文档的单词数越少,值越高

  3. BM25F 词频在整个文档集中越稀少,词频越高, 文档的单词数越少,权重越高,值越高