1. 项目背景与核心价值
《红楼梦》作为中国古典文学巅峰之作,其文本结构复杂、人物关系交错、隐喻丰富。传统文学研究多依赖人工细读,而现代文本分析技术能帮助我们从海量文字中发现隐藏模式。这个项目展示了如何用Python实现从原始文本处理到关键词提取的全流程,特别适合对文学计算感兴趣的开发者和人文研究者。
我最初尝试这个方法是为了解决一个具体问题:如何客观比较不同章回的主题侧重?手工标注不仅耗时,还容易受主观影响。通过TF-IDF算法,我们能够量化词语在不同章节中的重要性差异,这种数据驱动的视角往往能揭示出意想不到的文本特征。
2. 文本预处理实战
2.1 原始文本获取与清洗
优质的分析始于干净的文本数据。我推荐使用中国哲学书电子化计划的《红楼梦》电子版,其校对质量较高且保留原版分卷结构。下载后需要处理:
python复制import re
def clean_text(text):
# 去除标点、数字等非中文内容
text = re.sub(r'[^\u4e00-\u9fa5]', '', text)
# 合并连续空格
text = re.sub(r'\s+', ' ', text)
return text.strip()
with open('hongloumeng.txt', 'r', encoding='utf-8') as f:
raw_text = f.read()
cleaned_text = clean_text(raw_text)
注意:古典文本中存在大量异体字,如"纔"与"才",建议统一转换为简体字后再分析。可使用opencc-python进行转换:
bash复制pip install opencc-python-reimplemented
2.2 分卷处理技巧
《红楼梦》的120回版本通常分为三卷,准确切分是后续分析的基础。我开发了基于回目特征的分割方法:
python复制def split_volumes(text):
volume_markers = [
'第[一二三四五六七八九十]+回', # 回目正则
'卷[一二三四五六七八九十]+之', # 部分版本卷标记
'【.*?】' # 章节标记
]
pattern = '|'.join(volume_markers)
volumes = re.split(pattern, text)[1:] # 首项为空
return volumes[:3] # 取前三卷
volumes = split_volumes(cleaned_text)
print(f"各卷字数统计:{[len(v) for v in volumes]}")
实际操作中发现,某些版本的回目与正文混排会导致分割错误。我的解决方案是先提取所有回目位置,再按固定回数(如40回/卷)划分,这种方法对多数版本都适用。
3. 关键词分析技术实现
3.1 分词优化策略
古典文学分词需要特殊处理。测试发现,通用分词器对"黛玉葬花"这类专名识别不佳。我的解决方案是:
- 加载自定义词典:包含所有主要角色名、地名、诗词名
- 调整隐马尔可夫模型参数:提高未登录词识别率
- 后处理合并:将"林/黛玉"强制合并为"林黛玉"
python复制import jieba
# 加载自定义词典
jieba.load_userdict('hlm_dict.txt')
def improved_cut(text):
words = jieba.lcut(text)
# 合并角色全名
merged = []
i = 0
while i < len(words):
if i+1 < len(words) and words[i]+words[i+1] in character_names:
merged.append(words[i]+words[i+1])
i += 2
else:
merged.append(words[i])
i += 1
return merged
3.2 TF-IDF算法深度适配
传统TF-IDF需要针对文学文本做三处改进:
- 去除高频虚词:创建停用词表包含"之乎者也"等文言虚词
- 词性过滤:仅保留名词、动词等实词
- 章节长度归一化:消除不同章节字数差异的影响
python复制from sklearn.feature_extraction.text import TfidfVectorizer
import jieba.posseg as pseg
class ClassicalTFIDF(TfidfVectorizer):
def build_analyzer(self):
def analyzer(doc):
words = pseg.cut(doc)
return [word for word, flag in words
if flag in ['n', 'v', 'nr', 'ns']
and word not in stopwords]
return analyzer
tfidf = ClassicalTFIDF()
matrix = tfidf.fit_transform(volumes)
4. 分析结果与可视化
4.1 关键词对比分析
将各卷TF-IDF得分前20的词提取出来后,发现一些有趣现象:
| 卷序 | 特色关键词 | 文学意义 |
|---|---|---|
| 卷一 | 宝玉、黛玉、贾母、凤姐 | 人物关系建立期 |
| 卷二 | 抄检、大观园、诗社、海棠 | 冲突爆发与文化活动 |
| 卷三 | 掉包、出家、抄家、白茫茫 | 家族衰败与结局隐喻 |
通过这种对比,可以清晰看到叙事重心的转移:从人物介绍到矛盾冲突,最终走向悲剧结局。
4.2 交互式可视化
使用Pyecharts创建动态词云,能更直观展示各卷特征:
python复制from pyecharts import options as opts
from pyecharts.charts import WordCloud
def generate_wordcloud(keywords):
wc = (
WordCloud()
.add("", keywords, word_size_range=[20, 100])
.set_global_opts(title_opts=opts.TitleOpts(title="红楼梦分卷关键词"))
)
return wc
volume1_words = [(word, score) for word, score in zip(tfidf.get_feature_names_out(), matrix[0].toarray()[0])]
generate_wordcloud(sorted(volume1_words, key=lambda x: x[1], reverse=True)[:50])
5. 实战经验与问题排查
5.1 常见问题解决方案
-
分词不准确:
- 现象:"贾宝玉"被拆分为"贾/宝玉"
- 解决:调整jieba的HMM参数,
jieba.enable_hmm(True)
-
TF-IDF得分异常:
- 现象:某些常见词得分过高
- 检查:停用词表是否完整,建议包含500+文言常用虚词
-
内存不足:
- 现象:处理大文本时崩溃
- 优化:使用
TfidfVectorizer(max_features=5000)限制特征数量
5.2 分析技巧进阶
- 历时性分析:将每10回作为一个时间窗口,观察关键词演变
- 人物网络构建:基于共现统计构建人物关系图
- 情感分析:使用LSTM模型分析各回情感倾向变化
python复制# 简单共现统计示例
from collections import defaultdict
co_occurrence = defaultdict(int)
window_size = 5
for i in range(len(words)-window_size):
window = words[i:i+window_size]
characters_in_window = set([w for w in window if w in main_characters])
for pair in itertools.combinations(characters_in_window, 2):
co_occurrence[tuple(sorted(pair))] += 1
6. 项目扩展方向
在实际应用中,我发现这套方法可以延伸出多个有价值的研究方向:
- 版本比对:对比程高本与脂评本的关键词差异
- 作者分析:通过用词习惯验证后40回作者争议
- 跨作品比较:与《金瓶梅》等作品进行主题对比
一个特别实用的技巧是将分析结果与红学研究成果对照。例如,通过TF-IDF发现"螃蟹"在第三十七回异常突出,对应着"薛宝钗讽和螃蟹咏"这一重要情节,这种算法与文本细读的结合往往能产生新的见解。
对于想深入的研究者,我建议尝试将传统的词频分析与现代的BERT等嵌入方法结合。最近我在试验用sentence-transformers计算段落语义相似度,初步结果显示能有效识别不同章回间的隐含关联。这需要更强的算力支持,但为古典文学研究提供了全新的技术路径。