当前位置: 首页 > news >正文

机器学习第十课之TF-IDF算法(红楼梦文本分析)

简介

       之前我们学习过jieba库,了解了它的分词功能 本次我们将聚焦于文本处理领域中极具影响力的算法 ——TF-IDF。在信息爆炸的时代,如何从海量文本中提取关键信息、衡量词语的重要性,TF-IDF 算法给出了经典答案,它也是文本分类、信息检索、关键词提取等任务的核心工具。我们会从算法的核心思想讲起,带你理解 “词频(TF)” 与 “逆文档频率(IDF)” 的真正含义。你将明白,为什么一个词语在某篇文档中出现次数越多(高 TF),同时在其他文档中出现次数越少(高 IDF),它就越能代表该文档的核心内容。我们会详细拆解 TF-IDF 的计算步骤,用具体的文本示例演示如何一步步算出每个词语的权重,让你对算法的数学逻辑一目了然。并且将以红楼梦的案例带你进一步了解TF-IDF算法

每天学习一个Python第三方库之jieba库

一、TF-IDF算法基本概念

1.TF:


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

举例:
假设一篇文章为《中国的蜜蜂养殖》,分词后有 1000 个词,"中国"、"蜜蜂"、"养殖" 各出现 20 次,则这三个词的 "词频"(TF)都为 0.02。

2.IDF:

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

3.TF-IDF:

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

举例

还是以《中国的蜜蜂养殖》为例,假定该文长度为 1000 个词,"中国"、"蜜蜂"、"养殖" 各出现 20 次,则这三个词的 "词频"(TF)都为 0.02。然后,搜索 Google 发现,包含 "的" 字的网页共有 250 亿张,假定这就是中文网页总数。包含 "中国" 的网页共有 62.3 亿张,包含 "蜜蜂" 的网页为 0.484 亿张,包含 "养殖" 的网页为 0.973 亿张。则它们的逆文档频率(IDF)和 TF-IDF 如下:

包含该词的文档数(亿)
IDFTF-IDF
中国62.30.6030.0121
蜜蜂0.4842.7130.0543
养殖0.9732.4100.0482

二、TF-IDF的应用

对于一个文本

1.首先导入了必要的库:

from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd

2.读取语料库:

inFile = open(r".\task2_1.txt", 'r')
corpus = inFile.readlines()

读取所有行内容到corpus变量中,corpus是一个包含多个文本的列表。

3.TF-IDF 向量化处理:

vectorizer = TfidfVectorizer()
tfidf = vectorizer.fit_transform(corpus)
print(tfidf)

  • 创建了 TF-IDF 向量化器对象
  • 使用fit_transform方法对语料库进行拟合和转换,得到 TF-IDF 矩阵(稀疏矩阵形式)

4.获取特征词列表:

wordlist = vectorizer.get_feature_names()
print(wordlist)

获取所有在语料库中出现的词语(特征词)列表,并打印出来。

5.转换为 DataFrame 进行查看:

df = pd.DataFrame(tfidf.T.todense(), index=wordlist)
print(df)

6.构建词语 - TF-IDF 值的 DataFrame 并排序:

  • 将 TF-IDF 矩阵转置并转换为稠密矩阵
  • 用词语列表作为索引构建 DataFrame,方便查看每个词在各文本中的 TF-IDF 值
featurelist = df.iloc[:, 5].to_list()
df_tfidf = pd.DataFrame({'word': wordlist,'tfidf': featurelist
})
df_sorted = df_tfidf.sort_values(by='tfidf', ascending=True)

三、案例分析

主要对《红楼梦》文本的分卷处理、分词分析以及 TF-IDF 关键词提取的操作

1.任务目标

将《红楼梦》文件按卷(章节)分隔为多个文件,使用 TF - IDF 算法提取每个文件的前 10 个关键词,具体步骤如下:

具体步骤

  1. 读取文件并定位到章节:对《红楼梦》文件进行读取操作,从中定位识别出各个章节的位置 。
  2. 读取章节,将章节名作为 .txt 文件名:提取每个章节的名称,以该名称创建对应的 .txt 格式文件,用于存储章节内容 。
  3. 将章节对应的内容存储到 .txt 文件:把每个章节对应的文本内容,写入到上一步创建好的同名 .txt 文件中 。
  4. 使用 TF - IDF 算法提取每个文件的前 10 个关键词:借助 TF - IDF(词频 - 逆文档频率)算法,对每个存储章节内容的 .txt 文件进行处理,计算出文件内词语的 TF - IDF 值,提取出每个文件中 TF - IDF 值排名前 10 的词语作为关键词 。

2.任务一:

《红楼梦》文本分卷处理

        现有一个关于红楼梦文章的全部文本,我们首先需要把每一节的内容给分离出来、一共120回也就是分离出120个txt文本,也就是后面的语料库。我们可以发现开头以及标题的下一场广告并不属于文章内容需要我们给处理。

import os  # 导入os模块,用于文件路径处理
file = open('红楼梦.txt', encoding='utf-8')  # 打开原始文本文件,指定utf-8编码
flag = 0  # 标志变量,用于控制第一个文件的创建
# 初始化一个文件对象,用于后续写入分卷内容
juan_file = open('红楼梦卷开头.txt', 'w', encoding='utf-8')# 逐行读取原始文件内容
for line in file:# 跳过包含广告内容的行和空行(数据清洗)if '手机电子书·大学生小说网' in line or line.strip() == '':continue# 检测到"卷 第"字样,说明是新一卷的开始if '卷 第' in line:# 以卷名作为文件名(如"卷 第一.txt")juan_name = line.strip() + '.txt'# 构建文件保存路径(保存在"分卷"文件夹下)path = os.path.join('.\\分卷', juan_name)print(path)  # 打印当前处理的卷文件路径# 处理第一个分卷的情况if flag == 0:# 创建并打开第一个分卷文件juan_file = open(path,'w',encoding='utf-8')# juan_file.write(line)  # 可选:是否将卷名写入文件flag = 1  # 更新标志,表明已处理第一个分卷else:# 处理后续分卷:先关闭上一卷文件,再创建新卷文件juan_file.close()juan_file = open(path,'w',encoding='utf-8')# juan_file.write(line)  # 可选:是否将卷名写入文件continue  # 跳过当前行(卷名)的写入,继续处理下一行# 将当前行内容写入对应的分卷文件juan_file.write(line)# 所有内容处理完毕,关闭最后一个分卷文件
juan_file.close()

关键细节

  • 使用line.strip()去除空白字符,确保准确判断空行
  • 通过os.path.join()构建跨平台兼容的文件路径
  • 使用flag变量特殊处理第一个分卷,避免初始文件对象的问题
  • 跳过广告内容和空行,保证分卷文本的纯净度

运行后我们就得到120个文件内容,一个文件就是红楼梦的一回内容

3.任务二:

文本分词与停用词过滤

得到文本后我们需要得到类似于下图的数据内容、有着标准的数据格式。

        而我们通过任务一只能得到下图的文章内容,并没有进行数据的分词处理,分词前又考虑到红楼梦并不像我们现在说的话一样,有自己的词库而且还有一些无关的词语与标点(如:的、吗)所以在使用jieba库进行分词前需要添加红楼梦的词库与去停用词

import pandas as pd  # 导入pandas,用于数据结构化处理
import os  # 导入os模块,用于文件遍历
import jieba  # 导入jieba分词库,用于中文分词# 初始化两个列表,分别存储文件路径和对应的内容
filePaths = []
fileContents = []# 遍历"分卷"文件夹下的所有文件
for root, dirs, files in os.walk(r"分卷"):for name in files:# 构建完整的文件路径filePath = os.path.join(root, name)filePaths.append(filePath)  # 将路径添加到列表# 读取文件内容f = open(filePath, 'r', encoding='utf-8')fileContent = f.read()  # 读取整个文件内容f.close()  # 关闭文件fileContents.append(fileContent)  # 将内容添加到列表# 构建DataFrame,将文件路径和内容关联起来,方便后续处理
corpos = pd.DataFrame({'filePath': filePaths,'fileContent': fileContents
})# 加载自定义分词词典,提高《红楼梦》专有名词的分词准确性
jieba.load_userdict(r"红楼梦词库.Txt")# 读取中文停用词表(如"的"、"了"等无实际意义的词)
stopwords = pd.read_csv(r"StopwordsCN.txt",encoding='utf8', engine='python', index_col=False)# 创建新文件,用于保存所有分卷的分词结果
file_to_jieba = open(r'分词后汇总.txt', 'w', encoding='utf-8')# 遍历DataFrame中的每一行(即每一卷的内容)
for index, row in corpos.iterrows():juan_ci = ''  # 用于存储当前卷的分词结果fileContent = row['fileContent']  # 获取当前卷的文本内容# 使用jieba对文本进行分词segs = jieba.cut(fileContent)# 过滤停用词和空字符串for seg in segs:# 检查词语是否不在停用词表中,且不是空字符串if seg not in stopwords.stopword.values and len(seg.strip()) > 0:juan_ci += seg + ' '  # 将有效词语用空格连接# 将当前卷的分词结果写入汇总文件,每行对应一卷file_to_jieba.write(juan_ci + '\n')# 关闭汇总文件
file_to_jieba.close()

关键细节

  • 使用os.walk()递归遍历文件夹,自动获取所有分卷文件
  • 用 DataFrame 结构化存储文件信息,便于后续索引和处理
  • jieba.load_userdict()加载专业词库,解决古籍专有名词识别问题
  • 停用词过滤通过not in stopwords.stopword.values实现,提升文本分析质量
  • 分词结果用空格连接,符合 TF-IDF 分析的输入格式要求

分词后我们就得到这样的语料库,这就是标准的语料库,一行就是代表着红楼梦的一回

4.任务三:

TF-IDF 特征提取与分析

数据集准备完成,接下来就可以进行TF-IDF 特征提取与分析了

from sklearn.feature_extraction.text import TfidfVectorizer  # 导入TF-IDF向量化工具
import pandas as pd  # 导入pandas用于数据处理# 读取分词后的汇总文件,获取语料库
inFile = open(r"分词后汇总.txt", 'r', encoding='utf-8')
corpus = inFile.readlines()  # 每一行对应一个分卷的分词结果
inFile.close()  # 关闭文件# 创建TF-IDF向量化器对象
vectorizer = TfidfVectorizer()
# 对语料库进行拟合(学习词汇表)并转换为TF-IDF矩阵
tfidf = vectorizer.fit_transform(corpus)
# 获取所有特征词(即分词后的所有词语)列表
wordlist = vectorizer.get_feature_names()# 将TF-IDF矩阵转置(词语为行,分卷为列)并转换为稠密矩阵,构建DataFrame
df = pd.DataFrame(tfidf.T.todense(), index=wordlist)# 遍历每个分卷,提取并打印TF-IDF值最高的前10个词语
for idx in range(len(corpus)):# 对第idx个分卷的所有词语按TF-IDF值降序排序,取前10个sorted_series = df[idx].sort_values(ascending=False).head(10)# 打印结果print("第{}篇文章TF-IDF值前十的为:".format(idx+1))print(sorted_series)

关键细节

最后我们就得到每一回的关键字也就是TF-IDF 最高的那个。

  • TfidfVectorizer会自动处理分词后的文本(空格分隔的词语序列)
  • fit_transform()返回的是稀疏矩阵(节省内存),通过todense()转换为稠密矩阵便于查看
  • 矩阵转置(T)是为了让词语作为行索引,分卷作为列,符合 "词语 - 分卷" 的分析视角
  • sort_values(ascending=False).head(10)实现了按重要性排序并取 top10 关键词
  • TF-IDF 值越高,表示该词语在当前分卷中出现频率高,而在其他分卷中出现频率低,更能代表该分卷的特征

总结

        详细的解释都放在代码里面了,可以根据慢慢的调试去理解代码的逻辑,尤其是对数据的处理需要仔细琢磨

http://www.dtcms.com/a/327819.html

相关文章:

  • 服务器节点技术解析:从架构原理到家庭实践的全维度指南
  • 文件IO函数实现
  • 异或和查询
  • 【报错处理】mount: /boot/efi: unknown filesystem type ‘LVM2_member‘.
  • ARM基础概念 异常处理01 day52
  • 前端项目一键换肤
  • Web 服务详解:HTTP 与 HTTPS 配置
  • SuperMap GIS基础产品FAQ集锦(20250804)
  • Java 中 Set 接口详解:知识点与注意事项
  • LangChain SQLChatMessageHistory:SQL数据库存储聊天历史详解
  • Day05 店铺营业状态设置 Redis
  • MQTTX使用wss的连接报错
  • Java -- List接口方法--遍历--ArrayList的注意事项
  • 贪心----4.划分字母区间
  • 方格网法土方计算不规则堆体
  • [ 前端JavaScript的事件流机制 ] - 捕获、冒泡及委托
  • 少数民族文字OCR识别技术实现及应用场景剖析
  • JMeter并发测试与多进程测试
  • __base__属性
  • ETCD的简介和使用
  • 42.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--扩展功能--集成网关--网关集成认证(一)
  • 1513-map 的三种声明定义方式 使用方式
  • BN层:深度学习中的“数据稳定器”,如何解决训练难题?
  • 基于C#的二手服装交易网站的设计与实现/基于asp.net的二手交易系统的设计与实现/基于.net的闲置物品交易系统的设计与实现
  • 嵌入式Linux学习 -- 软件编程3
  • UNet改进(32):结合CNN局部建模与Transformer全局感知
  • Docker 101:面向初学者的综合教程
  • 【C#】从 Queue 到 ConcurrentQueue:一次对象池改造的实战心得
  • 激活函数篇(2):SwiGLU | GLU | Swish | ReLU | Sigmoid
  • 如何查看当前Redis的密码、如何修改密码、如何快速启动以及重启Redis (Windows)