【机器学习】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 编码,特别是停用词表和自定义词库。

相关推荐
数智工坊1 小时前
周志华《Machine Learning》学习笔记--第四章--决策树
笔记·学习·机器学习
小脑斧1231 小时前
自媒体内容工业化:基于AI Skills低代码实现穿搭账号矩阵自动化量产
人工智能·低代码·媒体·skills·openclaw·hermes·marvis
填满你的记忆1 小时前
《为什么 MySQL 不适合做 AI 检索?》
数据库·人工智能·mysql·ai·向量数据库
Fleshy数模1 小时前
深度学习核心:神经网络
python
威尔逊·柏斯科·希伯理1 小时前
机器学习第二天(KNN)
人工智能·机器学习
winlife_1 小时前
让 AI 自动跑 PlayMode 回归测试:从 BUG 注入到自动判 FAIL 的完整闭环
人工智能·unity·bug·ai编程·mcp·回归测试·游戏测试
古月开发1 小时前
比价助手:截图自动全网比价与历史价格查询实战
人工智能·信息可视化·自动化
lqqjuly1 小时前
优化理论:梯度方法、约束优化与机器学习优化
人工智能·机器学习