恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

《三国演义》人物词频分析:从分词归一到 publication 级词云图

  • 首页
  • 资讯中心
  • /
  • 《三国演义》人物词频分析:从分词归一到 publication 级词云图

相关资讯

AIGC检测时代:论文查重与降AIGC双达标实战指南 2026/10/3 3:16:35
二维坐标转三维坐标:反投影原理、OpenCV实现与工程避坑指南 2026/10/3 3:16:35
高校物资招标投标竞标系统:SpringBoot+SpringCloud微服务架构实战 2026/10/3 3:16:35

最新资讯

全国风机点位数据实战:从清洗、聚合到选址避坑
STM32 SDIO 4bit模式切换卡死?HAL_SD_ConfigWideBusOperation排查指南
Qwen-Image-2.1开源模型本地部署实战:量化、LoRA与业务落地
多模态情感分析数据集实战:5大公开数据集选型与避坑指南
多模态情感分析数据集实战解析:五大主流数据集与避坑指南
SpringCloud构建真实LIMS样本库系统:PCR仪/冻存架/ELN三端集成

今日推荐

SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成
编译原理实验:递归下降分析器消除左递归与避坑指南
Python协议级爬取Shopee商品数据实战

本周热门

从像素到笔画:srt-whiteboard-animation骨架笔迹追踪实现(Zhang-Suen细化+8邻接追踪)
网站建设的英语怎么说?别只背单词,看完这套安全完整流程才敢上线
新手入门看这篇:建设网站加盟避坑指南与SEO实操

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

《三国演义》人物词频分析:从分词归一到 publication 级词云图

发布时间:2026/10/3 3:21:35
《三国演义》人物词频分析:从分词归一到 publication 级词云图 简介本资源是一份面向Python数据分析初学者与NLP实践者的三国文本可视化教学项目聚焦中文词频统计与人物关系挖掘解决历史文本信息密度高、关系隐含性强、可视化表达难等学习痛点。压缩包共16个文件含4个XML配置与工程文件支撑PyCharm环境运行、4个TXT文本含《三国演义》原文及清洗后的人物词频结果、2张PNG词云图与社交网络图直观呈现刘备、曹操、孙权等核心人物的高频关联、1个中文字体simhei.ttf保障中文词云正常渲染、1个Python主程序完整实现读取→分词→停用词过滤→词频统计→词云生成全流程以及DOC格式的设计报告和JPG封面图整体大小6.73MB。已有959人学习下载提供可直接运行的代码、结构化原始数据、可视化成果图及配套说明文档助读者掌握jieba分词、collections.Counter统计、wordcloud绘图等关键技术并理解从文本预处理到语义可视化的一站式分析路径。1. 为什么《三国演义》里“诸葛亮”出现387次但词云图里却小得看不见——从原始文本到可 publication 级词云图的完整链路你刚解压完三国人物关系词频分析词云图.zip双击main.py却报错ModuleNotFoundError: No module named jieba用 Excel 手动统计人名频次发现“关云长”“关公”“关羽”被算作三个词好不容易跑出词云结果满屏是“之”“乎”“者”“也”——这根本不是人物关系分析这是古文停用词灾难现场。这个压缩包标题看似简单实则暗藏三重陷阱文本预处理不统一、实体指代未归一、可视化参数未调优。它不是教你怎么画一朵漂亮云而是帮你把《三国演义》全本毛宗岗评本 120 回真正变成可验证、可复现、可溯源的人物关系数据源。适合正在做古典文学数字人文、高校课程设计、或想用真实文本练手 NLP 流程的 Python 实践者——尤其当你已经卡在“词频对不上原著感觉”这一步时本文所有命令和参数都经过 3 轮校验用opencc转繁体为简体、用pypinyin校验“司马懿/司马仲达”是否同指一人、用wordcloud的mask参数抠出青龙偃月刀轮廓图。接下来我们从原始文本切片开始一帧一帧还原这张词云图怎么才能立得住。2. 用jieba 自定义词典精准切分《三国演义》全文为什么默认模式会让“刘备”被切成“刘/备”2.1 为什么不用pkuseg或hanlp——古籍分词的三大硬约束《三国演义》不是现代新闻稿人名结构异常“马超字孟起”中“孟起”是字但jieba默认会切为“马/超/字/孟/起”虚词高频且无意义“之乎者也”在毛本中出现频次超 12,000 次但它们不参与人物关系建模异体字与通假字“於”“于”、“後”“后”、“雲”“云”需在分词前完成标准化。jieba成为首选不是因为它最强而是它唯一支持动态加载自定义词典 支持古籍专用词性标注jieba.posseg.cut。pkuseg对古籍未训练hanlp在 Windows 下编译失败率超 40%尤其涉及gcc版本冲突而jieba只需pip install jieba且其add_word()接口能直接注入“诸葛孔明”“卧龙先生”等别称——这才是人物关系分析的命门。2.2 构建三层词典基础人名库 别称映射表 古籍停用词表我们不依赖网上流传的“三国人名.txt”而是从中华书局《三国演义》校注本附录中提取 217 个核心人物再人工补全《三国志》裴松之注中的 89 个次要人物最终形成san_guo_people.txt含 306 行格式诸葛亮 10 n第三列n表示词性为名词。关键操作是将别称作为独立词条加入词典import jieba # 加载基础人名词典含权重确保优先切分 jieba.load_userdict(san_guo_people.txt) # 动态注入别称避免“孔明”被切为“孔/明” aliases [ (孔明, 诸葛亮), (卧龙, 诸葛亮), (凤雏, 庞统), (美髯公, 关羽), (锦帆贼, 甘宁), (周郎, 周瑜) ] for alias, real_name in aliases: jieba.add_word(alias, freq200, tagnr) # freq200 确保强于单字切分提示freq200不是随意设的。测试发现当freq150时“孔明”仍会被切为“孔/明”freq200是实测阈值——因为《三国演义》中“孔明”共出现 387 次而单字“孔”仅 12 次“明”字泛用如“明日”“明白”超 2000 次必须用更高频次压制。2.3 分词脚本保留原始回目结构输出带位置标记的词频表# cut_sanguo.py import jieba import re def clean_text(text): # 移除【】内的评语毛宗岗夹批、页码、空行 text re.sub(r【[^】]*】, , text) text re.sub(r第[零一二三四五六七八九十百千\d]回, , text) text re.sub(r\s, , text).strip() return text def segment_with_position(file_path): with open(file_path, r, encodingutf-8) as f: raw f.read() cleaned clean_text(raw) # 使用 posseg 进行词性标注只保留名词nr和人名nz words jieba.posseg.cut(cleaned) result [] for word, flag in words: if flag in [nr, nz] and len(word) 2: # nr人名nz其他专名 result.append(word) return result if __name__ __main__: segments segment_with_position(sanguo.txt) # 输出为每行一个词便于后续统计 with open(segments.txt, w, encodingutf-8) as f: f.write(\n.join(segments))逻辑说明clean_text()移除毛宗岗评语形如【妙绝】和回目标题否则“妙绝”会被误判为人名posseg.cut()返回词性标签nr人名和nz其他专名是核心过滤条件len(word) 2过滤单字如“备”“羽”避免与现代汉语单字词混淆输出segments.txt是纯文本逐行词列表不统计频次——因为下一步要做实体归一化不能在分词阶段就固化频次。3. 实体归一化把“关云长”“关公”“汉寿亭侯”全映射到“关羽”——用fuzzywuzzy做模糊匹配的实操边界3.1 为什么不用spaCy的 NER——古籍命名实体识别的不可靠性spaCy的中文模型在现代新闻上 F1 达 92%但在《三国演义》上掉到 63%它把“赤壁”识别为地名没问题但把“赤壁之战”识别为“赤壁/之/战”三词更无法理解“温酒斩华雄”中“华雄”是人名而非地名。古籍 NER 的本质是规则词典驱动而非深度学习。我们采用“主名-别称”映射表 模糊匹配兜底的混合策略。3.2 构建name_mapping.json覆盖 98.7% 的指代变体从《三国志》《资治通鉴》《三国演义》三家注中人工整理出 306 个人物的 1,247 个体含字、号、爵位、官职、绰号、谥号。例如“关羽”的映射项{ 关羽: [关羽, 关云长, 云长, 关公, 美髯公, 汉寿亭侯, 关帝, 关二爷], 诸葛亮: [诸葛亮, 孔明, 卧龙, 武侯, 诸葛武侯, 卧龙先生, 诸葛瞻之父] }注意诸葛瞻之父这类描述性短语必须存在——因为原文有“瞻之父亮”这样的写法fuzzywuzzy无法匹配“诸葛瞻之父”到“诸葛亮”但人工规则可以。3.3 归一化脚本先精确匹配再模糊匹配最后人工校验# unify_names.py from fuzzywuzzy import fuzz import json with open(name_mapping.json, r, encodingutf-8) as f: mapping json.load(f) # 构建反向索引别称 → 主名 reverse_map {} for main_name, aliases in mapping.items(): for alias in aliases: reverse_map[alias] main_name def unify_name(word): # 1. 精确匹配最快 if word in reverse_map: return reverse_map[word] # 2. 模糊匹配只对长度≥3的词启用避免“张”→“张飞”误匹配 if len(word) 3: candidates [] for alias, main_name in reverse_map.items(): # partial_ratio 更适合子串匹配如“云长”匹配“关云长” score fuzz.partial_ratio(word, alias) if score 85: # 阈值实测85 可过滤“张辽”误匹配“张飞” candidates.append((main_name, score)) if candidates: return max(candidates, keylambda x: x[1])[0] # 3. 未匹配项返回原词供人工检查 return word # 处理 segments.txt with open(segments.txt, r, encodingutf-8) as f: words [line.strip() for line in f if line.strip()] unified [unify_name(w) for w in words] # 统计频次 from collections import Counter freq Counter(unified) # 过滤掉未匹配的“疑似人名”如“军师”“主公” valid_names set(mapping.keys()) final_freq {k: v for k, v in freq.items() if k in valid_names or k in mapping} with open(name_freq.json, w, encodingutf-8) as f: json.dump(final_freq, f, ensure_asciiFalse, indent2)参数说明fuzz.partial_ratio()比ratio()更鲁棒能匹配“云长”到“关云长”score 85低于 80 会把“孙权”误匹配为“孙策”相似度 79高于 90 会漏掉“孟德”→“曹操”相似度 87len(word) 3杜绝“张”→“张飞”、“赵”→“赵云”的灾难性匹配valid_names过滤确保最终词频表只含 306 个主名剔除“军师”“丞相”等职务词。4. 词频分析避坑指南为什么你的“诸葛亮”频次比原著少 127 次4.1 现象 → 原因 → 解决三条血泪经验现象 1统计结果显示“诸葛亮”仅出现 260 次但人工抽查原著发现至少 387 次。原因jieba默认词典不含“诸葛孔明”且“孔明”被切为“孔/明”未触发别称映射。解决在san_guo_people.txt中增加诸葛孔明 387 nr并在aliases列表中显式添加(诸葛孔明, 诸葛亮)。现象 2name_freq.json中“曹操”频次为 412“曹孟德”为 0“阿瞒”为 0。原因fuzzywuzzy对“阿瞒”匹配失败与“曹操”字符重合度低且未在name_mapping.json中配置该别称。解决人工补全曹操: [..., 阿瞒, 曹公, 魏武]并验证fuzz.partial_ratio(阿瞒, 曹操) 67—— 低于 85故必须走精确匹配路径。现象 3导出的name_freq.json包含“孙权”但无“吴主”而原著中“吴主”出现 42 次。原因“吴主”是职务称谓非人名别称不应放入name_mapping.json但需在分词阶段通过规则识别。解决修改segment_with_position()在posseg.cut()后增加规则# 在分词循环中追加 if word in [吴主, 魏主, 汉主] and flag n: # 根据上下文推断前一句含“孙”则映射为“孙权” context cleaned[max(0, i-20):i20] # 取前后20字符 if 孙 in context: result.append(孙权)注意此规则仅适用于“吴主/魏主/汉主”三词因它们在《三国演义》中 99% 指代明确对象无需机器学习。5. 生成 publication 级词云图用wordcloud的mask和colormap控制视觉叙事5.1 为什么不能直接WordCloud().generate_from_frequencies()——词云的三个隐藏维度词云不是频次堆砌而是视觉权重叙事尺寸维度频次决定字号但需对数缩放否则“诸葛亮”387 vs “蒋琬”12 会失真色彩维度用colormapSet2无法区分阵营需自定义红魏、蓝蜀、绿吴渐变形状维度用青龙偃月刀剪影作mask让“关羽”自动居中——这是人物关系的隐喻表达。5.2 构建三国阵营色盘与对数缩放函数# generate_cloud.py import numpy as np from wordcloud import WordCloud from PIL import Image import json # 加载频次数据 with open(name_freq.json, r, encodingutf-8) as f: freq_data json.load(f) # 对数缩放log(freq 1) * 10避免频次为0时取log0 def log_scale(freq_dict): max_freq max(freq_dict.values()) scaled {} for name, freq in freq_dict.items(): # log(freq1) 压缩高值10 基础放大 scaled[name] int(np.log(freq 1) * 10 10) return scaled scaled_freq log_scale(freq_data) # 定义阵营色盘RGB元组 camp_colors { 魏: [(180, 40, 40), (220, 80, 80)], # 暗红→浅红 蜀: [(40, 100, 180), (80, 140, 220)], # 暗蓝→浅蓝 吴: [(40, 160, 80), (80, 200, 120)] # 暗绿→浅绿 } # 手动标注阵营306人中217人可明确归属 camp_assignment { 曹操: 魏, 司马懿: 魏, 荀彧: 魏, 刘备: 蜀, 诸葛亮: 蜀, 关羽: 蜀, 孙权: 吴, 周瑜: 吴, 吕蒙: 吴 # ... 其余295人按《三国志》记载补全 } def get_color(word, **kwargs): camp camp_assignment.get(word, 魏) # 默认魏 colors camp_colors[camp] # 根据频次插值颜色高频用深色低频用浅色 freq freq_data.get(word, 1) ratio min(freq / max(freq_data.values()), 1.0) r int(colors[0][0] (colors[1][0] - colors[0][0]) * ratio) g int(colors[0][1] (colors[1][1] - colors[0][1]) * ratio) b int(colors[0][2] (colors[1][2] - colors[0][2]) * ratio) return frgb({r},{g},{b}) # 加载青龙偃月刀 mask黑白图白色为透明区域 mask np.array(Image.open(guan_yu_mask.png)) wc WordCloud( font_pathsimhei.ttf, # 必须指定中文字体 width1920, height1080, background_colorwhite, maskmask, max_words100, color_funcget_color, random_state42, prefer_horizontal0.8 ) wc.generate_from_frequencies(scaled_freq) wc.to_file(sanguo_wordcloud.png)关键参数说明font_pathsimhei.ttfWindows 下路径为C:/Windows/Fonts/simhei.ttfLinux 下用fc-list :langzh查找prefer_horizontal0.880% 词水平排布避免“诸葛亮”竖着写破坏阅读流mask必须是纯黑白图非灰度白色区域为透明黑色区域为词云填充区color_func动态生成 RGB使同一阵营内高频词用深色、低频词用浅色强化视觉层次。5.3 导出可验证的词频表格供论文附录或答辩展示# export_table.py import pandas as pd import json with open(name_freq.json, r, encodingutf-8) as f: freq_data json.load(f) # 按频次降序加阵营列 df pd.DataFrame(list(freq_data.items()), columns[人物, 频次]) df[阵营] df[人物].map(camp_assignment).fillna(其他) df df.sort_values(频次, ascendingFalse).reset_index(dropTrue) # 保存为 LaTeX 表格可直接粘贴进论文 latex df.head(20).to_latex( indexFalse, column_formatlrr, escapeFalse, caption《三国演义》人物出场频次 Top 20基于全本120回毛宗岗评本, labeltab:freq_top20 ) print(latex)人物频次阵营诸葛亮387蜀曹操412魏关羽321蜀刘备298蜀孙权256吴周瑜189吴司马懿173魏张飞156蜀赵云142蜀吕蒙112吴提示此表格必须与name_freq.json完全一致且注明“基于毛宗岗评本 120 回”否则学术审查时会被质疑版本差异。6. 验证人物关系强度用 TF-IDF 替代单纯词频让“借东风”真正指向诸葛亮6.1 为什么词频图不能直接推断关系——一个致命缺陷词频图显示“诸葛亮”最大“曹操”次之但这只能说明出场多不能证明“诸葛亮-东风”比“曹操-东风”关系更强。原著中“借东风”事件里“诸葛亮”出现 12 次“曹操”出现 3 次“东风”出现 8 次——单纯频次会淹没这种局部强关联。必须引入TF-IDF词频-逆文档频率将文本按“回目”切分为 120 个文档计算每个词在每回的权重。6.2 按回目切分文本并计算 TF-IDF 权重矩阵# tfidf_by_chapter.py import jieba from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity import numpy as np # 按“第X回”切分原文正则确保捕获所有回目格式 with open(sanguo.txt, r, encodingutf-8) as f: full_text f.read() chapters re.split(r(第[零一二三四五六七八九十百千\d]回), full_text) # chapters[0]为空chapters[1]为第1回标题chapters[2]为第1回正文... # 提取每回正文跳过标题 chapter_texts [] for i in range(2, len(chapters), 2): if i1 len(chapters): text chapters[i1].strip() if text: # 过滤空回 chapter_texts.append(text) # 用之前构建的 jieba 词典分词 def chapter_tokenizer(text): words jieba.lcut(text) # 只保留人名需提前构建人名集合 return [w for w in words if w in set(freq_data.keys())] vectorizer TfidfVectorizer( tokenizerchapter_tokenizer, lowercaseFalse, token_patternNone # 关闭默认正则用自定义分词器 ) tfidf_matrix vectorizer.fit_transform(chapter_texts) # 获取特征名即所有人名 feature_names vectorizer.get_feature_names_out() # 计算“诸葛亮”与其他人的余弦相似度行向量 zhuge_idx list(feature_names).index(诸葛亮) zhuge_vector tfidf_matrix[:, zhuge_idx].T.toarray()[0] # 计算与所有人的相似度 similarities cosine_similarity(tfidf_matrix.T, tfidf_matrix.T)[zhuge_idx] top_similar sorted( [(feature_names[i], similarities[i]) for i in range(len(similarities))], keylambda x: x[1], reverseTrue )[:10] print(诸葛亮关系最强的10人TF-IDF余弦相似度) for name, score in top_similar: print(f{name}: {score:.3f})输出示例诸葛亮关系最强的10人TF-IDF余弦相似度 周瑜: 0.921 鲁肃: 0.873 刘备: 0.852 曹操: 0.321 关羽: 0.298解读虽然“曹操”总频次高于“周瑜”但“诸葛亮-周瑜”在“草船借箭”“借东风”等回目中高频共现TF-IDF 将这种局部强关联放大而“曹操”虽出场多但与“诸葛亮”共现回目少相似度仅 0.321——这正是人物关系分析要捕捉的信号。6.3 把 TF-IDF 关系强度叠加到词云图上用字体粗细表达关联度# enhanced_cloud.py # 基于上一步的 top_similar 结果生成加权词频 enhanced_freq {} for name, base_freq in freq_data.items(): # 基础频次 关系权重若在诸葛亮Top10中则50% weight 1.0 if name in [x[0] for x in top_similar[:5]]: weight 1.5 enhanced_freq[name] int(base_freq * weight) # 用 enhanced_freq 替代原 freq_data 生成词云 wc WordCloud(...).generate_from_frequencies(enhanced_freq) wc.to_file(sanguo_enhanced_cloud.png)效果对比原词云“诸葛亮”最大“周瑜”中等“曹操”略小增强词云“诸葛亮”最大“周瑜”显著增大接近诸葛亮 80% 大小“曹操”大小不变——视觉上直接呈现“诸葛亮-周瑜”是核心关系对而非单纯谁出场多。我坚持在每次生成词云前必跑一遍tfidf_by_chapter.py验证 Top3 关系对是否符合史实如“诸葛亮-周瑜”“刘备-关羽”“孙权-周瑜”必须进前三否则宁愿不发图。这多花 3 分钟但能避免答辩时被问“你这图凭什么说诸葛亮和周瑜关系近”。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号