如下图,是红楼梦的本文小说,现在我们要提取出红楼梦每卷排名前十的关键词

为了更顺利的完成要求,我们将任务拆解为以下四个节点
-
将这个文件中上下卷共120卷拆分开,每一卷内容保存为一个新的文本文件,文件名是相应卷名 ,所有卷放入文件夹 .\红楼梦
-
打印出每卷地址与内容
-
对每一卷进行分词
-
计算TF-IDF值,保存每卷TOP10关键词
(快速跳转)
拆分红楼梦120卷并另存
步骤:
-
按卷分割文件:
-
代码通过检测每一行是否包含
卷 第
,来判断是否需要开始一个新的分卷文件。 -
每个分卷文件以卷名命名,并保存在
红楼梦分卷
目录下。
-
-
初始文件:
-
代码会先创建一个临时文件
红楼梦开头.txt
,用于保存尚未分卷的内容。 -
如果发现
卷 第
后,会关闭临时文件,并开始按卷保存内容。
-
-
文件路径:
- 使用
os.path.join
生成分卷文件的完整路径,确保路径跨平台兼容。
- 使用
-
文件操作:
- 使用
open()
打开文件,write()
写入文件,close()
关闭文件。
- 使用
代码:
python
import os
# 打开《红楼梦》的原始文本文件,指定编码为utf-8
file = open('红楼梦.txt', encoding='utf-8')
# 设置一个标志变量flag,用于判断是否需要创建新的分卷文件
flag = 0
# 打开一个临时文件'红楼梦开头.txt',用于保存未分卷的内容
chapter_file = open('.\红楼梦开头.txt', 'w', encoding='utf-8')
# 逐行读取《红楼梦》的原始文件
for line in file:
# 检查当前行是否包含"卷 第",这是分卷的标志
if '卷 第' in line:
# 提取卷名,并去掉空白字符,生成分卷文件的名称
chapter_name = line.strip() + '.txt'
# 生成分卷文件的完整路径,保存在`红楼梦分卷`目录下
path = os.path.join('.\\红楼梦分卷\\', chapter_name)
print(path) # 打印分卷文件的路径
# 如果flag为0,表示这是第一个分卷,直接创建并写入文件
if flag == 0:
chapter_file = open(path, 'w', encoding='utf-8')
flag = 1 # 将flag置为1,表示已开始分卷
else:
# 如果flag不为0,表示之前已经有分卷文件了,先关闭当前文件
chapter_file.close()
# 再创建一个新的分卷文件
chapter_file = open(path, 'w', encoding='utf-8')
# 跳过本行,不将分卷标志行写入分卷文件
continue
# 将当前行写入分卷文件
chapter_file.write(line)
# 循环结束后,关闭最后一个分卷文件
chapter_file.close()
运行结果:
1)分卷

2)红楼梦未分卷的内容
打印分卷地址与内容
步骤:
-
文件遍历:
-
使用
os.walk
遍历.\红楼梦分卷
目录及其子目录下的所有文件。 -
对每个文件,获取其完整路径并打印。
-
-
文件读取:
-
打开文件并读取所有行。
-
跳过前两行(从第3行开始)拼接文件内容。
-
-
数据存储:
- 将文件路径和文件内容分别存储在列表
filePaths
和fileContents
中。
- 将文件路径和文件内容分别存储在列表
-
创建 DataFrame:
- 使用
pandas
将文件路径和文件内容组合成一个DataFrame
。
- 使用
-
输出结果:
- 打印
DataFrame
,显示文件路径和文件内容的对应关系。
- 打印
代码:
python
import pandas as pd
import os
# 初始化两个列表,分别用于存储文件路径和文件内容
filePaths = []
fileContents = []
# 使用 os.walk 遍历指定目录('.\红楼梦分卷')及其子目录中的所有文件
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')
lines = f.readlines() # 读取文件的所有行
fileContent = ''.join(lines[2:]) # 从第3行开始拼接文件内容(跳过前两行)
f.close() # 关闭文件
fileContents.append(fileContent) # 将文件内容添加到列表中
# 使用 pandas 创建一个 DataFrame,包含文件路径和文件内容
corpos = pd.DataFrame({
'filePath': filePaths, # 文件路径列
'fileContent': fileContents # 文件内容列
})
# 打印 DataFrame
print(corpos)
运行结果:

对每一卷进行分词
步骤:
-
加载自定义词典:
-
使用
jieba.load_userdict
加载红楼梦词库.txt
,确保分词时能正确识别《红楼梦》中的专有词汇(例如人名、地名等)。
-
-
读取停用词表:
-
使用
pandas
读取停用词表StopwordsCN.txt
,停用词是分词后需要过滤掉的无意义词(例如"的"、"了"、"是"等)。
-
-
遍历文件内容:
- 通过
corpos.iterrows()
遍历corpos
DataFrame 中的每一行,获取文件路径和文件内容。
- 通过
-
分词处理:
-
使用
jieba.cut
对文件内容进行分词。 -
遍历分词结果,过滤掉停用词和空白词(长度为 0 的词)。
-
-
保存分词结果:
- 将处理后的分词结果写入到
红楼梦分词后汇总.txt
文件中。
- 将处理后的分词结果写入到
代码:
python
import jieba
# 加载自定义词典,确保分词结果符合《红楼梦》的专有词汇
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')
# 遍历 corpos DataFrame 中的每一行
for index, row in corpos.iterrows():
juan_ci = '' # 初始化一个空字符串,用于保存当前卷的分词结果
filePath = row['filePath'] # 获取当前文件路径
fileContent = row['fileContent'] # 获取当前文件内容
# 使用 jieba 对文件内容进行分词
segs = jieba.cut(fileContent)
# 遍历分词结果,去除停用词和空白词
for seg in segs:
# 如果当前词不是停用词且长度大于 0,则保留
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()
运行结果:
1)运行成功界面

2)红楼梦分词后汇总.txt

计算TF-IDF值并保存每卷中top10关键词
步骤:
-
读取分词结果:
- 打开分词后的汇总文件
红楼梦分词后汇总.txt
,读取所有行作为语料库。
- 打开分词后的汇总文件
-
计算 TF-IDF 值:
- 使用
TfidfVectorizer
对语料库进行向量化,生成 TF-IDF 矩阵。
- 使用
-
获取词汇列表:
- 使用
get_feature_names_out()
获取所有词汇(特征词)。
- 使用
-
转换为 DataFrame:
- 将 TF-IDF 矩阵转换为
DataFrame
,转置是为了让每一列对应一卷,每一行对应一个词汇。
- 将 TF-IDF 矩阵转换为
-
提取核心关键词:
- 遍历每一卷,提取其 TF-IDF 值最高的前 10 个核心关键词。
-
保存结果:
- 将每回的核心关键词 TOP10 写入文件
红楼梦分节关键词排名TOP10.txt
。
- 将每回的核心关键词 TOP10 写入文件
代码:
python
# 导入所需的库
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
# 打开分词后的汇总文件,读取所有行作为语料库
inFile = open(r'.\红楼梦分词后汇总.txt', 'r', encoding='utf-8')
corpus = inFile.readlines() # 语料库,每个元素是一行(即一卷的分词结果)
# 初始化 TfidfVectorizer,用于计算 TF-IDF 值
vectorizer = TfidfVectorizer()
# 使用语料库计算 TF-IDF 矩阵
tfidf = vectorizer.fit_transform(corpus)
# 获取所有词汇(特征词)
wordlist = vectorizer.get_feature_names_out() # 注意:`get_feature_names` 已弃用,推荐使用 `get_feature_names_out`
# 将 TF-IDF 矩阵转换为 DataFrame,便于后续操作
# 转置矩阵是为了让每一列对应一卷,每一行对应一个词汇
df = pd.DataFrame(tfidf.T.todense(), index=wordlist)
# 打开文件,用于保存每回的核心关键词排名
file_keywords = open(r'.\红楼梦分节关键词排名TOP10.txt', 'w', encoding='utf-8')
# 遍历每一卷,提取其核心关键词 TOP10
for i in range(len(corpus)):
# 获取当前卷的 TF-IDF 值列表
featurelist = df.iloc[:, i].to_list()
# 初始化一个字典,用于存储词汇及其对应的 TF-IDF 值
resdict = {}
# 将词汇和 TF-IDF 值一一对应
for j in range(0, len(wordlist)):
resdict[wordlist[j]] = featurelist[j]
# 对字典按 TF-IDF 值进行降序排序
resdict = sorted(resdict.items(), key=lambda x: x[1], reverse=True)
# 将当前卷的核心关键词 TOP10 写入文件
file_keywords.write(f'第{i+1}回的核心关键词:' + str(resdict[0:10]) + '\n')
# 如果需要在控制台打印结果,可以取消注释以下代码
print('第{}回的核心关键词:'.format(i+1), resdict[0:10])
# 关闭关键词文件
file_keywords.close()
运行结果:
