【机器学习】NLP---用 Python+TF-IDF 给《红楼梦》自动提取关键词

文章目录


前言

在信息爆炸的时代,快速从文本中抓取核心信息的能力非常重要。TF-IDF 是 NLP 领域最经典、也最容易上手的关键词提取算法之一。本文将带你从零开始,完成从文本读取、分词、去停用词,到使用 TF-IDF 提取每一回关键词的全过程,代码清晰易懂,有需要可直接运行。


一、项目准备与整体流程

概念介绍

TF-IDF(词频 - 逆文档频率)是一种统计方法,用来评估一个词在文本中的重要程度:

  • TF(词频):这个词在当前文本中出现的次数。出现越多,TF 越高。

  • IDF(逆文档频率):这个词在所有文本中出现的频率。出现的文本越少,IDF 越高。

  • TF-IDF 值 = TF × IDF:值越高,代表这个词对当前文本的区分度越大,越可能是关键词。

项目准备

首先,确保你已经安装了项目所需的 Python 库。打开终端执行以下命令:

c 复制代码
pip install pandas jieba scikit-learn
  • pandas:用于数据处理和表格操作

  • jieba:中文分词神器,专门处理中文文本

  • scikit-learn:提供 TF-IDF 算法的实现

为了让项目顺利运行,我们先把文件都准备好,放在同一个文件夹下:

分卷,中存放着红楼梦所有章回

StopwordsCN,中存放着中文停用词表(比如"的、了、是"这类无意义词)

分词后汇总,用来保存分词后的文本

红楼梦词库,是自定义词库,帮助jieba更好地识别专有名词

二、第一步:读取文本并分词(红楼梦关键字检索.py

这部分代码负责把分卷文件夹里的所有《红楼梦》文本读出来,用jieba分词,再去掉停用词,最后保存成一个干净的文本文件。

c 复制代码
import pandas as pd
import os

# 1. 读取所有文件路径和内容
filePaths = []
fileContents = []
for root, dirs, files in os.walk('分卷'):
    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()

        # 去掉第一行标题,只保留正文内容(根据你的文件格式调整)
        lines = fileContent.splitlines()
        fileContent = "\n".join(lines[1:])
        fileContents.append(fileContent)

# 2. 把文件路径和内容存入DataFrame,方便后续处理
corpos = pd.DataFrame({
    'filePaths': filePaths,
    'fileContents': fileContents
})
print("成功读取文件,共{}个文本".format(len(corpos)))

# 3. 加载自定义词库和停用词表
import jieba
jieba.load_userdict('红楼梦词库.txt')  # 告诉jieba《红楼梦》里的专有名词,比如"贾宝玉"
stopwords = pd.read_csv('StopwordsCN.txt', encoding='utf-8', engine='python', index_col=False)

# 4. 打开一个新文件,准备写入分词后的结果
file_to_jieba = open('分词后汇总.txt', 'w', encoding='utf-8')

# 5. 遍历每个文本,分词+去停用词
for index, row in corpos.iterrows():
    fileContents = row['fileContents']
    segs = jieba.cut(fileContents)  # 对文本进行分词
    jian_ci = ''
    for seg in segs:
        # 过滤掉停用词和空白字符
        if seg not in stopwords.stopword.values and len(seg.strip()) > 0:
            jian_ci += seg + ' '  # 用空格把分词结果连起来
    file_to_jieba.write(jian_ci + '\n')  # 每回文本占一行

file_to_jieba.close()
print("分词完成,结果已保存到'分词后汇总.txt'")
  1. 批量读取文件:os.walk会自动遍历分卷文件夹里的所有.txt文件,把每个文件的路径和内容存起来。

  2. 清洗文本:lines1:去掉了文件的第一行标题,只保留正文内容。

  3. 加载词库:jieba.load_userdict可以让分词器识别《红楼梦》里的人名、地名等专有名词,避免把 "贾宝玉" 拆成 "贾""宝""玉"。

  4. 去停用词:像 "的、了、是、我、你" 这类高频但无实际意义的词,会被过滤掉,只保留有信息量的词。

  5. 保存结果:分词后的文本会被写成一行一个文本,方便后续 TF-IDF 读取。

三、第二步:用 TF-IDF 提取关键词(红楼梦关键字提取.py

这部分代码会读取上一步生成的分词后汇总.txt,使用scikit-learn的TfidfVectorizer计算每个词的 TF-IDF 值,最后为每一回文本提取 TOP10 关键词。

c 复制代码
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd

# 1. 读取分词后的文本数据
inFile = open(r'.\分词后汇总.txt', 'r', encoding='utf-8')
corpus = inFile.readlines()  # 每一行是一回文本
print("成功读取{}个文本".format(len(corpus)))

# 2. 初始化TF-IDF模型
vectorizer = TfidfVectorizer()
# 拟合数据并计算TF-IDF矩阵
tfidf = vectorizer.fit_transform(corpus)

# 3. 获取所有词的列表
wordlist = vectorizer.get_feature_names_out()

# 4. 把TF-IDF矩阵转换成DataFrame,方便查看和处理
df = pd.DataFrame(tfidf.T.todense(), index=wordlist)

# 5. 遍历每一回文本,提取TOP10关键词
for j in range(len(corpus)):
    # 获取当前文本中所有词的TF-IDF值
    featurelist = df.iloc[:, j].to_list()
    # 把词和对应的TF-IDF值存成字典
    resdict = {}
    for i in range(0, len(wordlist)):
        resdict[wordlist[i]] = featurelist[i]
    # 按TF-IDF值从高到低排序
    resdict = sorted(resdict.items(), key=lambda x: x[1], reverse=True)
    # 取前10个作为关键词
    top10 = resdict[:10]
    print("第{}回的TOP10关键词:".format(j+1))
    print(top10)

核心步骤

  • TfidfVectorizer():初始化 TF-IDF 模型,参数用默认值就可以,非常方便。

  • fit_transform(corpus):模型会学习所有文本的词频,并计算出每个词的 TF-IDF 值。

  • get_feature_names_out():获取所有出现过的词,作为后续排序的索引。

  • DataFrame(tfidf.T.todense()):把稀疏矩阵转成普通表格,方便我们查看和排序。

  • sorted(resdict.items(), key=lambda x: x1, reverse=True):按 TF-IDF 值从高到低排序,取前 10 个就是关键词啦。

四、运行结果示例

c 复制代码
[('士隐', 0.44813777205112726), ('雨村', 0.1591461377160705), ('弟子', 0.13985916684686453), ('道人', 0.12699873793774877), ('那僧', 0.12237677099100645), ('英莲', 0.11173783977712862), ('那僧道', 0.10489437513514839), ('一段', 0.09793608474835107), ('封肃', 0.09311486648094051), ('空空道人', 0.09311486648094051)]
[('尤氏', 0.23866936440258454), ('鸳鸯', 0.2044460822953718), ('林之孝家的', 0.19750641940904387), ('奶奶', 0.17814015246070256), ('贾母', 0.15255642022708202), ('太妃', 0.13674765484916634), ('周瑞家的', 0.13557973470592935), ('喜鸾', 0.13151470995577685), ('南安', 0.13079210176877828), ('司棋', 0.11527013414232981)]
[('宝玉', 0.34342932566889794), ('晴雯', 0.3135073747865914), ('王夫人', 0.21705862584865596), ('司棋', 0.210447634912385), ('周瑞家的', 0.1980213502705289), ('袭人', 0.16147604616317685), ('太太', 0.1350587005280526), ('芳官', 0.10757495210650907), ('迎春', 0.10055457383772931), ('干娘', 0.08199748579817936)]

可以看到,提取出的关键词基本都能对应上每一回的核心人物和事件,同时还输出了每个关键字的权重,权重越接近1,代表越重要。


总结

代码运行中我们需要注意检查文件路径是否正确,特别是分卷文件夹、红楼梦词库.txt和StopwordsCN.txt是否和代码在同一个文件夹,同时确保所有文件都是 UTF-8 编码,特别是停用词表和自定义词库。

相关推荐
兵慌码乱3 小时前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理
ZhengEnCi4 小时前
09c-斯坦福CS336作业二:系统与分布式训练
人工智能
阿里云大数据AI技术4 小时前
用 SQL 解锁多模态数据分析:Hologres 让图片、语音、视频变成结构化洞察
人工智能
阿里云大数据AI技术4 小时前
EMR Serverless StarRocks 湖仓多模态检索:One SQL on One Data,实现全文 + 标量 + 向量三路混合检索
人工智能
金銀銅鐵5 小时前
[Python] 体验用欧几里得算法计算最大公约数的过程
python·数学
冬奇Lab6 小时前
Skill 系列(02):Skill 安全风险——三类攻击面的实战测试
人工智能·安全·开源
冬奇Lab6 小时前
每日一个开源项目(第138篇):OpenMontage - 把 AI 编程助手变成完整的视频制作团队
人工智能·开源·claude
米小虾6 小时前
智谱港股盘中市值突破万亿港元!GLM-5.2 开源引爆国产 AI 价值重估
人工智能·chatglm (智谱)
阿里云大数据AI技术6 小时前
义乌小商品城基于MaxFrame AI Function的亿级AI 数据产线提速之路
人工智能