文本检索-TFIDF

Posted by Orchid on February 17, 2025

TF-IDF(Term Frequency-Inverse Document Frequency) 是一种经典的文本特征提取算法,广泛应用于信息检索、文本分类、推荐系统等场景。它通过计算词语在文档中的重要性,帮助我们理解文本的主题,并可用于自动文本分类和推荐。

数学原理

该方法结合了两个方面的信息:词项在文档中的频率(TF)和在整个文档集合中的逆文档频率(IDF)。

  1. 词项在文档中的频率(TF)

    \[\begin{equation} TF(t,d)=\frac{词项t在文档d中出现的次数}{文档d中所有词项的总数} \end{equation}\]

    其中,$t$ 表示词项,$d$ 表示文档。$TF$ 表示了一个词项在文档中的相对频率,即在文档中出现的次数相对于文档总词项数的比例。

  2. 逆文档频率(IDF)

    \[\begin{equation} IDF(t)=log(\frac{文档集合中的文档总数}{包含词项t的文档数 + 1}) \end{equation}\]

    其中,$t$ 表示词项。$IDF$ 表示了一个词项在整个文档集合中的稀有程度,如果词项在许多文档中都出现,其IDF值较低,反之则较高。

  3. TFIDF的计算

    \[\begin{equation} TFIDF(t,d,D)=TF(t,d)×IDF(t) \end{equation}\]

    其中,$D$ 表示文档集合。$TFIDF$ 的最终值是将词项在文档中的频率和在整个文档集合中的逆文档频率相乘,这样可以得到一个更全面的评估,既考虑了在文档中的重要性,也考虑了在整个文档集合中的稀有性。

scikit-learn的python实现

TfidfVectorizer

1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
    'This is the first document.',
    'This document is the second document.',
    'And this is the third one.',
    'Is this the first document?',
]
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus)
print("词语列表:", vectorizer.get_feature_names_out())
print("TF-IDF矩阵形状:", X.shape)
print("TF-IDF值:\n", X.toarray())

output:

1
2
3
4
5
6
7
8
9
10
11
词语列表: ['and' 'document' 'first' 'is' 'one' 'second' 'the' 'third' 'this']
TF-IDF矩阵形状: (4, 9)
TF-IDF值:
 [[0.         0.46979139 0.58028582 0.38408524 0.         0.
  0.38408524 0.         0.38408524]
 [0.         0.6876236  0.         0.28108867 0.         0.53864762
  0.28108867 0.         0.28108867]
 [0.51184851 0.         0.         0.26710379 0.51184851 0.
  0.26710379 0.51184851 0.26710379]
 [0.         0.46979139 0.58028582 0.38408524 0.         0.
  0.38408524 0.         0.38408524]]
  • X 是一个稀疏矩阵,每一行对应一个文档,每一列对应一个词语

  • 注意,基本代码只能用于英语语料

中文语料库的信息检索

需要手动使用jieba库对中文语料进行分词。

jieba 是一个非常流行的中文分词库,用于将中文文本分割成单独的词语。它广泛应用于自然语言处理(NLP)任务中,如文本分析、情感分析、机器翻译等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import jieba
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.preprocessing import normalize

# 对提问和PDF内容进行分词
question_words = [' '.join(jieba.lcut(x['question'])) for x in questions]
pdf_content_words = [' '.join(jieba.lcut(x['content'])) for x in pdf_content]

tfidf = TfidfVectorizer()
tfidf.fit(question_words + pdf_content_words)

# 提取TFIDF
question_feat = tfidf.transform(question_words)
pdf_content_feat = tfidf.transform(pdf_content_words)

# 进行归一化
question_feat = normalize(question_feat)
pdf_content_feat = normalize(pdf_content_feat)

# 检索进行排序
for query_idx, feat in enumerate(question_feat):
    score = feat @ pdf_content_feat.T
    score = score.toarray()[0]
    max_score_page_idx = score.argsort()[-1] + 1
    questions[query_idx]['reference'] = 'page_' + str(max_score_page_idx)
  • tfidf.fit(question_words + pdf_content_words):建立词汇表,以及每个词项的 IDF
  • question_featTDIDF 稀疏矩阵,每一行对应question中的每一个文档,每一列对应一个词语
  • pdf_content_featTDIDF 稀疏矩阵,每一行对应pdf_content中的每一个文档,每一列对应一个词语