查看全课大纲(第 17 / 69 节)
- 1.NLP 的研究领域、应用与学习路径
- 2.自然语言的基本术语
- 3.信息论基础:信息熵与交叉熵
- 4.语言的进化与语义变迁
- 5.主观概率、客观概率与条件概率
- 6.贝叶斯原理与推理
- 7.随机变量:二项式、期望方差与联合概率
- 8.常见概率分布
- 9.辛普森悖论与贝叶斯解题实例
- 10.语言模型:语言概率与词袋模型
- 11.n-gram 语言模型(二元 / 三元 / N-Gram)
- 12.语言模型评价:交叉熵、困惑度与插值
- 13.朴素贝叶斯文本分类:垃圾邮件
- 14.拼写检查
- 15.中文分词:构词法、最大匹配、最优路径与 Jieba
- 16.词表示问题与语义相似度
- 17.TF-IDF 权重处理
- 18.One-Hot 表达与词表示的局限
- 19.Word2Vec 核心思想
- 20.Word2Vec 训练过程
- 21.Skip-gram 模型详解
- 22.词性标注任务与标注方法(规则 + N-Gram)
- 23.EM 算法与混合模型
- 24.高斯混合模型 GMM
- 25.从混合模型到隐马尔可夫模型
- 26.隐马尔可夫模型(HMM)推导与维特比解码
- 27.线性链条件随机场 CRF
- 28.贝叶斯网络与图模型
- 29.隐马尔可夫链与 HMM 推导
- 30.PLSA 主题模型
- 31.LSI 与 SVD 向量表达
- 32.LDA 与狄利克雷分布
- 33.主题模型实验复现(困惑度 / 分类 / 相似度 / 延展)
- 34.上下文无关文法(CFG)与句法分析
- 35.概率上下文无关文法 PCFG
- 36.统计机器翻译:词对齐与翻译模型
- 37.统计机器翻译中的对齐模型与参数估计
- 38.从统计机器翻译到神经机器翻译
- 39.神经元与反向传播速览(指向深度学习课)
- 40.CNN 原理及其在 NLP 中的应用
- 41.循环神经网络的基本原理与 Elman / Jordan 网络
- 42.LSTM:长短期记忆网络的核心思想与分步实现
- 43.Encoder-Decoder 框架
- 44.Seq2Seq 与早期注意力机制
- 45.注意力机制的背景与动机
- 46.注意力模型实现原理与匹配函数
- 47.记忆网络:组成与计算
- 48.注意力机制的应用与历史延展
- 49.Transformer 结构:Encoder-Decoder 栈与 Self-Attention
- 50.Multi-Head Attention、FFNN 与位置编码
- 51.层归一化、损失函数与 Universal Transformer 延展
- 52.预训练范式:从 ELMo 到 BERT
- 53.BERT 与掩码语言模型
- 54.BERT 下游任务微调与 GLUE 口径
- 55.GPT 与自回归语言建模
- 56.GPT-1 到 GPT-4 的演进
- 57.指令微调与 RLHF
- 58.分词器:BPE、WordPiece 与中文词表
- 59.上下文窗口与长文本处理
- 60.能力边界、成本与适用场景
- 61.文本分类实战:从朴素贝叶斯到逻辑回归
- 62.命名实体识别实战
- 63.文本生成与摘要实战
- 64.语义检索与向量库实战
- 65.RAG 知识库问答
- 66.NLP 评估指标:BLEU / ROUGE / BERTScore 与人工评估
- 67.幻觉与事实性问题
- 68.文本与知识结合(知识图谱压缩)
- 69.跨媒体信息检索与未来展望
TF-IDF 权重处理
小象实战讲义 · 自然语言处理
在上一节中,我们学习了基于计数的词表示方法,它通过统计一个词在特定上下文窗口中的共现频率来构建词向量。然而,简单的计数存在一个明显问题:它平等地对待所有词,忽略了不同词在表达文档主题时的重要性差异。例如,“the”、“a”等高频词虽然出现次数多,但对区分文档内容几乎毫无帮助。本节我们将引入自然语言处理和信息检索领域一个经典且至关重要的权重计算方法——TF-IDF,它能有效衡量一个词在特定文档集合中的相对重要性,是构建更高质量词向量和文档向量的关键一步。
💡 核心导读
- TF-IDF 的核心思想:一个词的重要性与其在当前文档中出现的频率(TF) 成正比,与在整个文档集合中出现的文档频率(DF) 成反比。
- TF(词频):衡量一个词在单个文档中的局部重要性。
- IDF(逆文档频率):衡量一个词在整个文档集合中的全局区分能力。越常见的词,IDF值越低。
- TF-IDF 的计算与应用:掌握TF-IDF的公式,理解其如何通过TF与IDF的乘积来综合评估词的重要性,并了解其在词表示和文档检索中的基础作用。
从简单计数到加权表示
在基于计数的词表示方法中,我们构建了一个“词-上下文”共现矩阵。矩阵中的每个元素 C[i, j] 表示目标词 i 在上下文词 j 的特定窗口内出现的次数。这种表示方法简单直接,但存在一个根本性的缺陷:它假设所有的共现关系同等重要。
实际上,有些上下文词(如“the”、“is”、“of”)几乎出现在所有目标词的上下文中,它们与目标词的共现计数很高,但并不能提供有意义的语义信息。相反,一些特定的上下文词(如“purred”对于“kitten”,“bit”对于“dog”)虽然共现次数可能不多,却能强烈地指示目标词的语义类别。
因此,我们需要一种方法来区分哪些高计数是真正信息丰富的,哪些仅仅是背景噪声。TF-IDF正是为了解决这个问题而设计的经典权重归一化方法之一。
TF-IDF:词重要性的经典度量
TF-IDF,全称 Term Frequency–Inverse Document Frequency,是一种用于信息检索与文本挖掘的常用加权技术。它评估一个词对于一个文档集或一个语料库中的其中一份文档的重要程度。
其基本思想是:如果一个词在一篇文档中出现的频率高,并且在其他文档中很少出现,则认为此词具有很好的类别区分能力,对当前文档的重要性高。
1. 词频(Term Frequency, TF)
词频衡量的是一个词在单个文档中出现的频繁程度。直觉上,一个词在文档中出现的次数越多,它对于该文档的主题可能就越重要。
有多种方式计算TF,最常见的一种是归一化词频,即一个词的词频除以该文档的总词数,以消除文档长度的影响。
公式定义: 给定一个词(term)t 和一篇文档 d,词 t 在文档 d 中的词频 TF(t, d) 可以计算为:
其中:
- 是词
t在文档d中出现的次数(原始频次)。 - 是文档
d中所有词出现次数的总和,即文档的总词数。
因此,TF(t, d) 表示词 t 在文档 d 中出现的相对频率或概率。
2. 逆文档频率(Inverse Document Frequency, IDF)
逆文档频率衡量的是一个词在整个文档集合中的普遍重要性。如果一个词在越多的文档中出现,说明它越常见,其区分不同文档内容的能力就越弱,因此应该赋予较低的权重。
公式定义: 给定一个文档集合 D,词 t 的逆文档频率 IDF(t, D) 计算如下:
其中:
- 是文档集合
D中的文档总数。 - 是包含词
t的文档数量(即文档频率,Document Frequency, DF)。为了避免分母为零,实际实现中常对分母做加一平滑处理。
对数(通常以自然对数或10为底)的作用是:当词出现在几乎所有文档中时(DF ≈ N),IDF值趋近于0;当词只出现在极少数文档中时(DF很小),IDF值会很大,从而放大其重要性。
3. TF-IDF 权重
最终,词 t 对于文档 d 在文档集 D 中的 TF-IDF 权重,是 TF 和 IDF 的乘积:
直观理解:
- 高 TF-IDF 值:意味着该词在当前文档中出现频繁(高TF),但在整个文档集合中并不常见(高IDF)。这类词通常是能代表文档主题的关键词。 例子:在圣经文本中,“耶稣”一词出现频率高,但在菜单、说明书等其它类型文本中极少出现,因此“耶稣”在圣经文档中的TF-IDF值会很高。
- 低 TF-IDF 值:
- 可能是常见词(如“the”、“is”),它们虽然TF可能不低,但IDF极低。
- 也可能是罕见词,在当前文档中只出现一两次(低TF),即使IDF高,整体权重也不高。
通过TF-IDF加权,我们能够抑制常见词的权重,提升具有区分力的关键词的权重,从而得到更能反映文档语义内容的词向量或文档向量表示。
动手计算 TF-IDF
下面我们通过一个简单的例子,用Python手动计算TF-IDF值,以加深理解。我们将使用一个微型文档集合。
import math
# 定义一个小型文档集合(每个文档已分词为词列表)
docs = [
['the', 'cat', 'sat', 'on', 'the', 'mat'], # Doc 0
['the', 'dog', 'chased', 'the', 'cat'], # Doc 1
['the', 'kitten', 'purred', 'and', 'sat', 'on', 'the', 'mat'] # Doc 2
]
# 文档总数
N = len(docs)
print(f"文档总数 N = {N}")
# 第一步:计算每个词的文档频率 DF (有多少个文档包含该词)
vocab = set()
for doc in docs:
vocab.update(doc)
vocab = sorted(list(vocab)) # 排序以便输出有序
df = {} # 文档频率字典
for word in vocab:
count = 0
for doc in docs:
if word in doc:
count += 1
df[word] = count
print(f"词 '{word}' 出现在 {count} 个文档中 (DF = {count})")
print("\n" + "="*40)文档总数 N = 3
词 'and' 出现在 1 个文档中 (DF = 1)
词 'cat' 出现在 2 个文档中 (DF = 2)
词 'chased' 出现在 1 个文档中 (DF = 1)
词 'dog' 出现在 1 个文档中 (DF = 1)
词 'kitten' 出现在 1 个文档中 (DF = 1)
词 'mat' 出现在 2 个文档中 (DF = 2)
词 'on' 出现在 2 个文档中 (DF = 2)
词 'purred' 出现在 1 个文档中 (DF = 1)
词 'sat' 出现在 2 个文档中 (DF = 2)
词 'the' 出现在 3 个文档中 (DF = 3)
========================================import math
# 重新构建同一微型文档集合(本块独立可运行,不引用上一块变量)
docs = [
['the', 'cat', 'sat', 'on', 'the', 'mat'], # Doc 0
['the', 'dog', 'chased', 'the', 'cat'], # Doc 1
['the', 'kitten', 'purred', 'and', 'sat', 'on', 'the', 'mat'] # Doc 2
]
N = len(docs)
# 文档频率 DF:每个词出现在多少个文档中
vocab = sorted({word for doc in docs for word in doc})
df = {}
for word in vocab:
df[word] = sum(1 for doc in docs if word in doc)
# 第二步:为每个文档计算每个词的 TF 和 TF-IDF
tfidf_results = {}
for doc_id, doc in enumerate(docs):
doc_total_words = len(doc)
tfidf_results[doc_id] = {}
# 计算当前文档中每个词的词频 TF
word_counts = {}
for word in doc:
word_counts[word] = word_counts.get(word, 0) + 1
# 计算 TF-IDF(标准 IDF: log(N / DF))
for word in set(doc):
tf = word_counts[word] / doc_total_words
idf = math.log(N / df[word])
tfidf = tf * idf
tfidf_results[doc_id][word] = (tf, idf, tfidf)
# 第三步:格式化输出结果
print("TF-IDF 计算结果 (TF, IDF, TF-IDF):")
print("-" * 60)
for doc_id in range(N):
print(f"\n文档 Doc{doc_id}: {docs[doc_id]}")
sorted_words = sorted(tfidf_results[doc_id].items(), key=lambda x: x[1][2], reverse=True)
for word, (tf, idf, tfidf) in sorted_words:
print(f" '{word}': TF={tf:.3f}, IDF={idf:.3f}, TF-IDF={tfidf:.4f}")TF-IDF 计算结果 (TF, IDF, TF-IDF):
------------------------------------------------------------
文档 Doc0: ['the', 'cat', 'sat', 'on', 'the', 'mat']
'cat': TF=0.167, IDF=0.405, TF-IDF=0.0676
'mat': TF=0.167, IDF=0.405, TF-IDF=0.0676
'sat': TF=0.167, IDF=0.405, TF-IDF=0.0676
'on': TF=0.167, IDF=0.405, TF-IDF=0.0676
'the': TF=0.333, IDF=0.000, TF-IDF=0.0000
文档 Doc1: ['the', 'dog', 'chased', 'the', 'cat']
'chased': TF=0.200, IDF=1.099, TF-IDF=0.2197
'dog': TF=0.200, IDF=1.099, TF-IDF=0.2197
'cat': TF=0.200, IDF=0.405, TF-IDF=0.0811
'the': TF=0.400, IDF=0.000, TF-IDF=0.0000
文档 Doc2: ['the', 'kitten', 'purred', 'and', 'sat', 'on', 'the', 'mat']
'and': TF=0.125, IDF=1.099, TF-IDF=0.1373
'purred': TF=0.125, IDF=1.099, TF-IDF=0.1373
'kitten': TF=0.125, IDF=1.099, TF-IDF=0.1373
'sat': TF=0.125, IDF=0.405, TF-IDF=0.0507
'mat': TF=0.125, IDF=0.405, TF-IDF=0.0507
'on': TF=0.125, IDF=0.405, TF-IDF=0.0507
'the': TF=0.250, IDF=0.000, TF-IDF=0.0000结果分析:
- 常见词“the”出现在全部 3 个文档中(DF=3),IDF = log(3/3) = 0,因此其 TF-IDF 权重在所有文档中都为 0,这符合预期:高频功能词不携带区分信息。
- 相对独特的词如“chased”、“dog”、“purred”、“kitten”具有较高的IDF值,尽管它们的TF可能不高,但最终的TF-IDF权重在各自文档中排名靠前。
- “cat”出现在两个文档中,其IDF低于只出现在一个文档中的词,因此其TF-IDF权重会受到抑制。
这个简单的例子清晰地展示了TF-IDF如何自动识别并提升文档中“关键词”的权重。
TF-IDF 在词表示中的应用与局限
在基于计数的词表示框架中,TF-IDF 可以作为一个强大的权重归一化步骤。原始的”词-上下文”共现矩阵 M(行是目标词、列是上下文词)里每个格子都换成对应的 TF-IDF 权重。这里两个轴的角色必须摆对,否则惩罚对象会整个搞反:
- 行(目标词)扮演”文档”:矩阵共有 N 行,N 就是 IDF 里的文档总数。
- 列(上下文词)扮演”文档中的词项”:
TF(c, t) = 共现计数(t, c) / 目标词 t 的总共现计数。 - 同一个上下文词 c 的 DF:
DF(c) = 这一列非零的目标词个数,即”有多少个目标词曾以 c 为上下文”。 - IDF 作用在上下文词上:
IDF(c) = log(N / DF(c))。
也就是说,被压低的是”到处都能当上下文”的泛词(the、a、is),保住的是”只跟少数目标词搭伴”的区分性上下文。反过来把上下文词当文档、让目标词当词项,DF 就变成”有多少个上下文词与目标词 t 共现”,IDF 惩罚的成了我们正要描述的那个目标词——语义越丰富的词越容易被压低,与 TF-IDF 的本意恰好相反。这是把 TF-IDF 搬到共现矩阵时最容易踩的坑。
TF-IDF的局限性:
- 无法捕捉词序和语义关系:它仍然基于词袋(Bag-of-Words)假设,忽略了词的顺序和句法结构。
- 对同义词和多义词处理不佳:“电脑”和“计算机”被视为完全不同的词,而多义词“苹果”(水果 vs. 公司)在不同语境下的重要性无法被区分。
- 依赖预定义的文档边界:在词表示中,如何定义“文档”是一个需要设计的问题(例如,使用滑动窗口作为伪文档)。
- 静态表示:一个词的TF-IDF向量是静态的,无法根据不同的上下文动态调整。
尽管有这些局限,TF-IDF因其简单、有效且无需训练的优点,至今仍在信息检索、文本分类、关键词提取等任务中作为基础特征被广泛使用。它也为后续更复杂的词嵌入方法(如Word2Vec)提供了重要的思想基础:即通过词的上下文分布来刻画词义,并需要对不同的上下文进行重要性加权。
📝 动手练一练
- 概念辨析:假设有两个词,“algorithm”和“the”,它们在某篇关于机器学习的论文中出现的原始次数相同。请问,在这篇论文中,哪个词的TF-IDF值很可能更高?为什么?
👉 点击查看参考答案
答案:“algorithm”的TF-IDF值很可能更高。
原因:
- 两者的TF(词频)可能相同或相近。
- 但是,它们的IDF(逆文档频率)会有显著差异。
- “the”是一个极其常见的功能词(停用词),几乎出现在所有英文文档中,因此它的文档频率(DF)极高,导致其IDF值非常低,甚至接近于零。
- “algorithm”是一个具有特定领域意义的词,它在通用文档(如小说、新闻)中出现的频率远低于“the”,因此其DF较低,IDF值较高。
- 根据公式 TF-IDF = TF × IDF,在TF相近的情况下,IDF更高的“algorithm”将获得更高的TF-IDF权重。这准确地反映了“algorithm”更能代表该机器学习论文的主题内容。
- 手算验证:根据上面Python示例中Doc0(
['the', 'cat', 'sat', 'on', 'the', 'mat'])的数据,请手动计算词“cat”在Doc0中的TF-IDF值(公式:,N=3,自然对数)。验证是否与程序输出(TF=0.167, IDF=0.405, TF-IDF=0.0676)一致。
👉 点击查看参考答案
计算过程:
计算 TF:
- 文档 Doc0 总词数 = 6。
- 词“cat”在 Doc0 中出现次数 = 1。
- 。
计算 IDF:
- 文档总数 N = 3。
- 包含“cat”的文档数 DF:“cat”出现在 Doc0 和 Doc1 中,所以 DF = 2。
- 。
计算 TF-IDF:
- 。
结论:手算结果 TF≈0.167, IDF≈0.405, TF-IDF≈0.0676,与程序输出一致。“cat”出现在两个文档中,IDF 低于只出现在一个文档中的词,因此其 TF-IDF 权重被相应抑制,符合 TF-IDF 的设计预期。
本章小结
本节我们深入探讨了TF-IDF权重处理技术,它是提升基于计数的词表示质量的关键一步。我们学习了:
- TF(词频) 反映了词在文档内部的局部重要性。
- IDF(逆文档频率) 反映了词在整个文档集合中的全局区分度,能有效抑制常见词的权重。
- TF-IDF 将两者结合,其值高的词通常是文档的关键词。
- 通过动手计算,我们直观感受了TF-IDF如何工作,并理解了它在构建词向量时作为共现计数权重归一化工具的价值。
TF-IDF的思想深远影响了许多后续的文本表示模型。尽管如今我们既有 Word2Vec 这类训练完成后同一词共用一个查表向量的静态嵌入,也有 BERT 这类随句子上下文动态生成表示的上下文表示,但TF-IDF所体现的“重要性加权”和“全局统计信息”的核心思想,在许多现代NLP系统的特征工程环节依然占有一席之地。
📋 行动清单
- 能够独立写出TF和IDF的计算公式,并解释每个变量的含义。
- 给定一个小型文档集和几个候选词,能定性判断谁的TF-IDF值可能更高。
- 在Python中,不依赖
sklearn等高级库,能根据公式手动实现TF-IDF的计算。
—— 小象教研组