三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

机器学习入门:TF-IDF

机器学习入门:TF-IDF

机器学习入门:TF-IDF

前言:本文是“机器学习入门”系列的第十站。前几篇我们学习了各种分类和聚类算法,但你会发现一个问题——这些算法处理的都是数值型数据。如果我们面对的是文本数据(如新闻、评论、邮件),该怎么办?计算机不认识文字,它只认识数字。本篇我们将学习如何把文本变成数字——这就是TF-IDF的作用。它是文本挖掘中最经典、最基础的特征提取方法,能将一篇文章“翻译”成一个数值向量,让后续的机器学习模型能够理解和处理文本数据。

目录

  • 一、认识 TF-IDF
  • 二、TF-IDF 的核心原理
  • 三、TF-IDF 的优缺点
  • 四、典型应用场景
  • 五、核心 API 速查
  • 六、实战案例:红楼梦各回关键词提取
  • 七、总结

一、认识 TF-IDF

1.1 什么是 TF-IDF?

TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频率)是一种文本特征提取技术。它的作用是将一段文本转换成一个数值向量,同时评估每个词对这篇文档的重要性。

通俗理解:想象你在读一篇关于“机器学习”的文章。如果“算法”这个词出现了很多次,它可能很重要——这是词频。但如果“的”、“是”这类词也出现很多次,它们其实没什么用。TF-IDF 会惩罚这些太常见的词,提升真正有区分度的词的权重——这是逆文档频率

TF-IDF 用于特征提取,是连接“原始文本”和“机器学习模型”的桥梁。

1.2 为什么需要 TF-IDF?

计算机不认识文字,只认识数字。如果我们要用机器学习处理文本(如垃圾邮件分类、新闻分类、情感分析),第一步就是把文本变成数字向量

最简单的想法是直接统计每个词在文档中出现的次数——出现次数越多,就认为这个词越重要。但这种方法有一个问题:像“的”、“是”、“在”这类词几乎每篇文档都有,频率很高,但对区分文档主题毫无帮助

TF-IDF 的巧妙之处在于:它会自动降低那些在很多文档中都出现的词的权重,提升那些只在少数文档中出现的词的权重。这样,真正能代表文档主题的关键词就被突显出来了。

二、TF-IDF 的核心原理

2.1 词频(TF,Term Frequency)

词频指的是某一个给定的词语在该文件中出现的次数。这个数字通常会被归一化(一般是词频除以文章总词数),以防止它偏向长的文件。

词频 ( T F ) = 某个词在文章中的出现次数 文章的总词数 \text{词频}(TF) = \frac{\text{某个词在文章中的出现次数}}{\text{文章的总词数}}词频(TF)=文章的总词数某个词在文章中的出现次数

直观理解:一个词在文档中出现次数越多,它在这篇文档中就越“重要”。

但仅靠 TF 是不够的——像 “this”、“is”、“the” 这类词虽然出现频繁,但没有任何区分度。

2.2 逆文档频率(IDF,Inverse Document Frequency)

IDF 的核心思想是:如果包含词条 t 的文档越少,IDF 越大,则说明词条具有很好的类别区分能力。

逆文档频率 ( I D F ) = log ⁡ ( 语料库的文档总数 包含该词的文档数 + 1 ) \text{逆文档频率}(IDF) = \log\left(\frac{\text{语料库的文档总数}}{\text{包含该词的文档数} + 1}\right)逆文档频率(IDF)=log(包含该词的文档数+1语料库的文档总数)

IDF 值含义
高 IDF该词出现在很少的文档中 → 稀有、有区分度 →重要
低 IDF该词出现在很多文档中 → 常见、区分性弱 →不重要

2.3 TF-IDF

因此,TF-IDF 倾向于过滤掉常见的词语,保留重要的词语。

T F − I D F = 词频 ( T F ) × 逆文档频率 ( I D F ) TF-IDF = \text{词频}(TF) \times \text{逆文档频率}(IDF)TFIDF=词频(TF)×逆文档频率(IDF)

总结:TF-IDF 值越高,说明该词在当前文档中既频繁出现,又具有区分度——它就是这篇文档的关键词。

2.4 计算示例

假设有以下 6 篇文档:

文档编号内容
D1This is the first document
D2This document is the second document
D3And this is the third one
D4Is this the first document
D5This line has several words
D6This is the final document

计算单词 “first” 在 D1 中的 TF-IDF:

Step 1:计算 TF

D1 总词数为 5,“first” 出现 1 次 → TF = 1/5 = 0.2

Step 2:计算 IDF

总文档数 N = 6,包含 “first” 的文档为 D1、D4(共 2 篇)→ IDF = log(6/(2+1)) = log(2) ≈ 0.301

Step 3:计算 TF-IDF

TF-IDF = 0.2 × 0.301 ≈ 0.060

再对比单词 “document” 在 D1 中的 TF-IDF:

  • TF = 1/5 = 0.2(同样出现 1 次)
  • IDF = log(6/(4+1)) = log(1.2) ≈ 0.079(在 D1、D2、D4、D6 中出现,共 4 篇)
  • TF-IDF = 0.2 × 0.079 ≈ 0.016

再对比单词 “this” 在 D1 中的 TF-IDF:

  • TF = 1/5 = 0.2(同样出现 1 次)
  • IDF = log(6/(6+1)) = log(0.857) ≈ -0.067(出现在所有 6 篇文档中,无区分度,IDF 接近 0)
  • TF-IDF = 0.2 × (-0.067) ≈ -0.013

结果对比

单词TF出现文档数IDFTF-IDF说明
“first”0.22 篇0.3010.060只在少数文档出现,区分度强,权重最高
“document”0.24 篇0.0790.016在多篇文档出现,区分度中等,权重中等
“this”0.26 篇-0.067-0.013在所有文档出现,无区分度,权重为负

这个示例说明:仅仅出现频率高并不代表重要,只有在特定文档中频繁出现且在其他文档中少见的词,TF-IDF 才会赋予高权重。TF-IDF 正是通过这种方式,过滤掉常见的词语,保留重要的词语。

三、TF-IDF 的优缺点

3.1 优点

  1. 简单高效:计算速度快,易于理解实现。
  2. 自动降权通用词:能自动降低“的”、“是”等高频无意义词的权重,突出关键词。
  3. 无需训练:不依赖任何模型,直接基于统计计算。
  4. 可解释性强:每个特征的权重都有明确含义。

3.2 缺点

  1. 忽略词序和语义:“我打你”和“你打我”的 TF-IDF 向量可能相同,但意思完全相反。
  2. 维度高:词汇量通常很大,导致特征向量非常稀疏。
  3. 丢失上下文信息:无法理解同义词和一词多义。

四、典型应用场景

  • 文本分类:将新闻、邮件、评论自动分类。
  • 信息检索:搜索引擎判断文档与查询词的相关性。
  • 关键词提取:自动提取一篇文章的核心关键词。
  • 文本聚类:将相似主题的文档归为一组。
  • 垃圾邮件过滤:判断邮件是否为垃圾邮件。

五、核心 API 速查

5.1 导包方式

fromsklearn.feature_extraction.textimportTfidfVectorizer

5.2 核心参数详解

参数名类型默认值说明
max_featuresint / NoneNone最大特征数,保留最重要的 N 个词,用于限制词汇量、降维
stop_wordsstr / listNone停用词,'english'使用内置停用词表,或自定义列表
ngram_rangetuple(1, 1)词组合范围,(1, 2) 表示同时考虑单个词和相邻双词组合
max_dffloat / int1.0忽略在超过此比例的文档中出现的词,用于过滤通用词
min_dffloat / int1忽略在少于此数量的文档中出现的词,用于过滤太生僻的词
use_idfboolTrue是否使用 IDF 加权
smooth_idfboolTrue平滑 IDF 计算,避免除零
sublinear_tfboolFalse使用亚线性 TF 缩放 log(1+TF)

5.3 常用属性

属性名说明
get_feature_names_out()返回所有特征词(词汇表)
vocabulary_词到索引的映射字典
idf_每个特征的 IDF 值

5.4 常用方法

方法名说明
fit_transform(X)训练并返回 TF-IDF 矩阵
transform(X)将新文档转换为 TF-IDF 向量(用已训练的参数)

六、实战案例:红楼梦各回关键词提取

6.1 案例背景

《红楼梦》作为中国古典文学的巅峰之作,全书共120回,每一回都有其独特的情节重点和核心人物。本案例利用 TF-IDF 对《红楼梦》每一回的内容进行关键词提取,帮助我们快速了解每一回的核心内容,为文学分析提供量化视角。

6.2 数据说明

数据说明
分卷目录每回一个文本文件,共120个文件
每回内容包含回目名称和正文内容
红楼梦词库自定义词典,确保人名、地名等专有名词被正确识别
停用词表过滤“的”、“了”、“是”等无意义词

6.3 完整代码

importosimportjiebaimportpandasaspdfromsklearn.feature_extraction.textimportTfidfVectorizer# ===================读取红楼梦分卷数据=========================filePaths=[]# 存储文件路径fileContents=[]# 存储文件内容forroot,dirs,filesinos.walk(r'.\红楼梦\分卷'):fornameinfiles:filePath=os.path.join(root,name)filePaths.append(filePath)withopen(filePath,'r',encoding='utf-8')asf:lines=f.read().splitlines()content=''.join(lines[2:])# 跳过前两行回目信息content=content.replace(' ','').replace('\t','')fileContents.append(content)corpos=pd.DataFrame({'filePath':filePaths,'fileContent':fileContents})print(f"共加载{len(corpos)}回内容")# ===================加载自定义词库与停用词=========================jieba.load_userdict(r'.\红楼梦\红楼梦词库.txt')# 加载红楼梦专属词库stopwords=pd.read_csv(r'.\红楼梦\StopwordsCN.txt',encoding='utf-8',engine='python',index_col=False)# ===================分词处理=========================corpos['cut_words']=''withopen(r'.\红楼梦\分词后汇总.txt','w',encoding='utf-8')asfile_to_jieba:forindex,rowincorpos.iterrows():juan_ci=''fileContent=row['fileContent']segs=jieba.cut(fileContent)# jieba分词forseginsegs:ifsegnotinstopwords.stopword.valuesandlen(seg.strip())>0:juan_ci+=seg+' 'file_to_jieba.write(juan_ci+'\n')corpos.loc[index,'cut_words']=juan_ci.strip()print("分词完成")# ===================读取分词结果=========================withopen(r'.\红楼梦\分词后汇总.txt','r',encoding='utf-8')asf:corpus=f.readlines()# ===================TFIDF向量化=========================vectorizer=TfidfVectorizer()tfidf=vectorizer.fit_transform(corpus)# 训练并转换为TFIDF矩阵wordlist=vectorizer.get_feature_names_out()# 获取词汇表df=pd.DataFrame(tfidf.T.todense(),index=wordlist)# 转为DataFrameprint(f"词汇表大小:{len(wordlist)}")print(f"TFIDF矩阵形状:{tfidf.shape}")# ===================各回提取Top10关键词=========================print("\n===== 各回 Top 10 关键词 =====")foriinrange(len(corpus)):featurelist=df.iloc[:,i].to_list()# 获取第i回所有词的TFIDF值resdict={}forjinrange(len(wordlist)):resdict[wordlist[j]]=featurelist[j]# 构建词-权重字典resdict=sorted(resdict.items(),key=lambdax:x[1],reverse=True)# 按权重降序排序print(f"\n第{i+1}回")forword,scoreinresdict[:10]:# 取前10个关键词print(f"{word}:{score:.4f}")
输出示例: 共加载 120 回内容 Building prefix dict from the default dictionary ... Loading model from cache C:\Users\Lenovo\AppData\Local\Temp\jieba.cache Loading model cost 0.983 seconds. Prefix dict has been built successfully. 分词完成 词汇表大小: 40260 TFIDF矩阵形状: (120, 40260) ===== 各回 Top 10 关键词 ===== 第1回 士隐: 0.4481 雨村: 0.1591 弟子: 0.1399 道人: 0.1270 那僧: 0.1224 英莲: 0.1117 那僧道: 0.1049 一段: 0.0979 封肃: 0.0931 空空道人: 0.0931 ...... 第120回 贾母: 0.2430 宝玉: 0.2287 牛黄: 0.2101 贾政道: 0.1893 薛姨妈: 0.1632 巧姐儿: 0.1625 凤姐: 0.1574 老太太: 0.1331 破题: 0.1313 贾政: 0.1217

6.4 关键步骤说明

步骤说明
数据加载遍历分卷目录,读取每回内容,跳过回目信息行
自定义词典加载红楼梦专属词库,确保人名、地名被正确分词
停用词过滤删除“的”、“了”、“是”等1000+个无意义词
分词处理使用 jieba 分词,结果写入文件并存入 DataFrame
TF-IDF 提取将分词后的文本转为 TF-IDF 向量,提取每回 Top 10 关键词

七、总结

核心知识点速查

知识点关键概念
TF-IDF文本特征提取方法,将文本转换为数值向量
TF(词频)词在当前文档中的出现频率
IDF(逆文档频率)惩罚高频通用词,奖励稀有区分词
TfidfVectorizersklearn 实现 TF-IDF 的工具类
max_features限制最大特征数,控制维度
ngram_range考虑单词组合,捕获短语信息

核心 API 一览

用途对应模块 / 方法
模型sklearn.feature_extraction.text.TfidfVectorizer
训练并转换fit_transform(X)
转换新文档transform(X)
特征词列表get_feature_names_out()
词汇表vocabulary_

注意事项

要点说明
中文需先分词中文没有空格分隔,需使用 jieba 等分词工具
停用词过滤必须去除“的”、“是”等无意义词,否则干扰结果
特征维度控制max_featuresmax_df/min_df控制维度
训练集/测试集分离fit_transform用于训练集,transform用于测试集

系列直达

  • 上篇:机器学习入门:DBSCAN 聚类
  • 本篇:机器学习入门:TF-IDF(本文)
  • 下篇:敬请期待
← 返回列表