三国人物关系词频分析与词云图:从文本到关系图谱的完整落地
简介这是一份面向Python文本分析与数据可视化学习者的三国人物关系词频分析实战资源围绕《三国演义》文本展开帮助读者掌握从原始文本到词云图与人物社交关系图的完整处理链路。压缩包共16个文件约6.73MB包含py分析脚本、txt文本与停用词表、ttf中文字体、png词云图与关系网络图、doc设计报告以及xml等工程配置覆盖代码、数据、成果与文档四类内容。项目涉及TXT文本读取、jieba分词、停用词与标点过滤、Counter词频统计、wordcloud词云生成等关键环节并延伸至人物社交关系网络的可视化呈现。已有959人学习下载适合具备Python基础、希望练习中文分词与NLP入门分析的读者参考可据此复现刘备、关羽、张飞及曹操、孙权等人物互动关系的量化结果理解文本预处理与统计可视化在实际项目中的衔接方式。1. 三国人物关系词频分析词云图从文本到关系图谱的完整落地拿到《三国演义》原文想搞清楚谁和谁互动最多、哪些人物是真正的“社交枢纽”光靠翻书肯定不现实。词频分析和词云图是两条最直接的路径词频告诉你哪些名字被反复提及词云把这种频率变成一眼可辨的视觉权重而人物关系分析则更进一步统计同一段落或同一句话里两个人名共现的次数从而推断关系的亲疏远近。这套方案适合有基础 Python 能力、想快速上手文本挖掘的开发者也适合需要做文学量化分析的研究者。整个流程不依赖复杂模型核心就是分词、统计、可视化三步但每一步都有细节决定最终图的质量。下面从数据准备开始把每个环节的参数和坑讲清楚。2. 数据准备与分词三国文本怎么切才不翻车2.1 语料获取与清洗的必做步骤《三国演义》的原文文本可以从公开古籍库获取常见格式是 txt 或 epub。拿到文本后第一件事不是直接分词而是清洗。原文里夹杂着大量非正文内容章节标题、页眉页脚、注释、标点符号混用。我一般会先用正则把“第X回”这类标题单独提取出来作为章节标记方便后续按回目做共现统计。清洗时重点处理三类噪声全角空格、换行符不统一、以及“曰”“云”这类对话标记后面紧跟的标点。如果不清洗分词工具会把“曰”和后面的人名粘在一起导致“关羽曰”被切成一个词人物名就丢了。import re def clean_text(raw_text): # 统一换行符 text raw_text.replace(\r\n, \n).replace(\r, \n) # 去掉全角空格和多余空白 text re.sub(r[ \s], , text) # 去掉括号注释如【】、内的内容 text re.sub(r[【(][^】)]*[】)], , text) # 保留中文、标点和换行去掉其他乱码 text re.sub(r[^\u4e00-\u9fa5。、“”‘’\n], , text) return text with open(sanguo.txt, r, encodingutf-8) as f: raw f.read() cleaned clean_text(raw)这段代码的逻辑是先统一格式再剔除注释和非法字符。参数上[^\u4e00-\u9fa5...]这个正则决定了保留哪些字符如果你用的文本里有生僻字或异体字需要把对应的 Unicode 范围加进去。清洗完的文本建议先打印前 500 字肉眼检查一遍确认没有把正文误删。2.2 分词工具选型与自定义词典中文分词工具常见的有 jieba、pkuseg、HanLP。做三国人物分析jieba 足够用但必须加载自定义词典。因为“诸葛亮”“司马懿”“夏侯惇”这些名字在通用词典里可能被切碎比如“诸葛”和“亮”分开“夏侯”和“惇”分开。自定义词典的格式是“词语 词频 词性”词频可以给一个较高的值确保不被切开。import jieba # 加载自定义人物词典 jieba.load_userdict(sanguo_names.txt) # 词典内容示例 # 诸葛亮 1000 nr # 司马懿 1000 nr # 夏侯惇 1000 nr # 关羽 1000 nr # 张飞 1000 nr def segment(text): words jieba.lcut(text) # 过滤掉单字和标点 words [w for w in words if len(w) 1 and not re.match(r^[。、“”‘’]$, w)] return words words segment(cleaned)这里的关键参数是len(w) 1因为单字在三国文本里大量出现但单字对人物关系分析几乎没有价值。如果你要做词云单字可以保留但做共现矩阵时一定要过滤。自定义词典需要你手动整理一份三国人物名单常见做法是从百科或公开的人物表里提取大概 200 到 300 个名字就够覆盖主要角色。2.3 词频统计与词云生成的最小命令词频统计用collections.Counter即可词云用wordcloud库。生成词云时有两个参数最影响效果font_path必须指定中文字体否则全是方块max_words控制显示多少个词一般设 100 到 200 之间太多会挤成一团。from collections import Counter from wordcloud import WordCloud import matplotlib.pyplot as plt word_counts Counter(words) # 取前 200 个高频词 top_words dict(word_counts.most_common(200)) wc WordCloud( font_pathsimhei.ttf, # 中文字体路径 width1200, height800, background_colorwhite, max_words200, colormapviridis, random_state42 ) wc.generate_from_frequencies(top_words) plt.figure(figsize(12, 8)) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.savefig(sanguo_wordcloud.png, dpi200, bbox_inchestight)generate_from_frequencies直接接受字典比从文本生成更可控。random_state固定后每次生成的布局一致方便对比不同参数的效果。保存时dpi200保证打印清晰度bbox_inchestight去掉多余白边。这一步跑完你就能得到一张基础词云图但人物关系还没体现出来。3. 人物关系共现矩阵谁和谁真正“同框”3.1 共现窗口的设定与滑动逻辑人物关系的核心是共现如果两个名字在同一个窗口内出现就认为他们有关系。窗口大小是关键参数。按段落切分是最自然的做法因为《三国演义》的段落通常围绕一个事件展开。但有些段落很长比如战争描写可能同时出现十几个人物这时候窗口太大关系会变得模糊。我一般用“句子级窗口 段落级回退”先按句号、问号、感叹号切分句子如果句子太短少于 10 个字就合并到相邻句子直到满足最小长度。这样既保留了对话中的紧密关系又不会把无关人物硬凑在一起。def split_sentences(text, min_len10): # 按中文标点切分 raw_sents re.split(r[。], text) sents [] buffer for s in raw_sents: s s.strip() if not s: continue buffer s if len(buffer) min_len: sents.append(buffer) buffer if buffer: sents.append(buffer) return sents sentences split_sentences(cleaned)min_len10是经验值低于这个长度说明句子信息量不足合并后能减少噪声。切分完的句子列表就是共现统计的基本单元。3.2 共现矩阵的构建与归一化有了句子列表和人物名单就可以构建共现矩阵。矩阵的行和列都是人物值是两个人在同一句子中出现的次数。注意要去重同一句话里“关羽”出现两次只算一次共现。归一化用 Jaccard 相似度或简单共现次数除以两人各自出现总次数的几何平均前者更稳健。import numpy as np import pandas as pd # 人物名单 with open(sanguo_names.txt, r, encodingutf-8) as f: names [line.split()[0] for line in f if line.strip()] name_set set(names) co_matrix pd.DataFrame(0, indexnames, columnsnames, dtypeint) for sent in sentences: present set() for name in names: if name in sent: present.add(name) present list(present) for i in range(len(present)): for j in range(i1, len(present)): co_matrix.loc[present[i], present[j]] 1 co_matrix.loc[present[j], present[i]] 1 # 归一化除以两人出现总次数的几何平均 total co_matrix.sum(axis1) norm_matrix co_matrix.copy().astype(float) for i in names: for j in names: if i ! j and total[i] 0 and total[j] 0: norm_matrix.loc[i, j] co_matrix.loc[i, j] / np.sqrt(total[i] * total[j])这段代码的效率在 200 人规模下完全够用如果人物名单扩大到 1000 人以上需要改用稀疏矩阵。归一化后的值在 0 到 1 之间越大表示关系越紧密。total[i]是第 i 个人物出现的总句子数几何平均能抑制高频人物的权重膨胀。3.3 关系网络图与词云图的叠加呈现共现矩阵可以直接导出成网络图用networkx加matplotlib画。节点大小对应人物词频边粗细对应归一化共现强度。如果想和词云结合可以把词云作为背景网络图叠加在上面但这样容易乱。更实用的做法是并排展示左边词云看频率右边网络图看关系。import networkx as nx G nx.Graph() for name in names: G.add_node(name, sizeword_counts.get(name, 0)) threshold 0.05 # 只保留归一化共现大于阈值的边 for i in names: for j in names: if i j and norm_matrix.loc[i, j] threshold: G.add_edge(i, j, weightnorm_matrix.loc[i, j]) pos nx.spring_layout(G, k0.8, seed42) node_sizes [G.nodes[n][size] * 2 for n in G.nodes] edge_widths [G.edges[e][weight] * 5 for e in G.edges] plt.figure(figsize(14, 10)) nx.draw_networkx_nodes(G, pos, node_sizenode_sizes, node_colorskyblue, alpha0.8) nx.draw_networkx_edges(G, pos, widthedge_widths, alpha0.5) nx.draw_networkx_labels(G, pos, font_size10, font_familySimHei) plt.axis(off) plt.savefig(sanguo_network.png, dpi200, bbox_inchestight)threshold0.05是过滤弱关系的阈值调高会让图更干净但可能丢失边缘人物。spring_layout的k参数控制节点间距值越大越分散。节点大小乘以 2 是为了视觉上更明显边宽乘以 5 同理。这张图能直观看出诸葛亮、曹操、刘备这些核心节点的连接密度。4. 避坑与排查词频分析和关系图常见的五个翻车点4.1 分词把人物名切碎导致词频失真现象词云里出现“诸葛”“司马”“夏侯”单独成词而“诸葛亮”频率很低。原因jieba 默认词典没有覆盖三国人物全名或者自定义词典加载失败。解决检查sanguo_names.txt的编码是否为 UTF-8每行格式是否为“词语 词频 词性”加载后打印jieba.lcut(诸葛亮)确认输出是完整名字。如果仍然切碎把词频调到 10000 以上强制优先匹配。4.2 词云中文显示为方块现象生成的词云图里所有汉字都是方框。原因font_path指向的字体不支持中文或者路径错误。解决用绝对路径指定中文字体Windows 常用C:/Windows/Fonts/simhei.ttfLinux 用/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc。确认文件存在后再跑不要用simsun.ttc这类可能缺失的字体。4.3 共现矩阵过于稀疏或过于稠密现象网络图要么只有几个孤立的点要么所有节点连成一团。原因共现窗口的min_len设置不当或者归一化阈值threshold不合理。解决先统计每句话平均包含多少个人物名如果平均超过 5 个说明窗口太大把min_len调低到 5 或按段落切分如果平均少于 1 个说明窗口太小调高到 20。阈值从 0.1 开始试观察边数变化。4.4 高频人物掩盖了次要人物的关系现象网络图里曹操、刘备、诸葛亮占据绝对中心其他人物几乎看不见。原因节点大小直接用了原始词频高频人物数值太大。解决对节点大小做对数变换np.log1p(word_counts)或者用归一化后的词频。边宽也做类似处理避免少数强边压过其他边。4.5 章节标题被当作人物名统计现象词频列表里出现“第一回”“宴桃园”这类词。原因清洗时没有去掉回目标题分词后这些词被保留。解决在清洗阶段用正则第[一二三四五六七八九十百]回匹配并删除或者在分词后过滤掉包含“回”“章”“节”的词。更彻底的做法是先把回目行单独提取不参与正文分词。5. 进阶技巧用 TF-IDF 和社区发现挖出隐藏关系基础共现矩阵只能看直接同框但三国里很多关系是间接的比如“关羽”和“曹操”通过“张辽”产生联系。这时候可以用 TF-IDF 加权和社区发现算法。TF-IDF 的思路是如果一个人物在某个章节里频繁出现但在全书里出现次数不多那他在这个章节里的权重应该更高。具体做法是把每个回目当作一篇文档计算每个人物在各回目的 TF-IDF 值然后用余弦相似度构建人物关系。社区发现用networkx的greedy_modularity_communities能自动把人物分成几个派系比如蜀汉、曹魏、东吴。from sklearn.feature_extraction.text import TfidfVectorizer from networkx.algorithms.community import greedy_modularity_communities # 按回目切分文档 chapters re.split(r第[一二三四五六七八九十百]回, cleaned) chapters [c for c in chapters if len(c) 100] # 每个人物作为一个特征词统计在各回目的出现次数 vectorizer TfidfVectorizer(vocabularynames, tokenizerlambda x: x.split(), lowercaseFalse) # 这里需要把每章文本转成空格分隔的词序列 chapter_words [ .join(segment(ch)) for ch in chapters] tfidf vectorizer.fit_transform(chapter_words) # 用 TF-IDF 矩阵的列向量计算人物相似度 from sklearn.metrics.pairwise import cosine_similarity sim cosine_similarity(tfidf.T) # 构建图并做社区发现 G2 nx.Graph() for i, name in enumerate(names): G2.add_node(name) for i in range(len(names)): for j in range(i1, len(names)): if sim[i, j] 0.3: G2.add_edge(names[i], names[j], weightsim[i, j]) communities greedy_modularity_communities(G2) for idx, comm in enumerate(communities): print(f社区 {idx1}: {, .join(comm)})vocabularynames强制只统计人物名tokenizer用空格切分是因为前面已经把词用空格连起来了。sim[i, j] 0.3是相似度阈值调低会纳入更多弱关系。社区发现的结果通常能把刘关张、曹操谋士团、孙权周瑜等分到不同组验证了算法的有效性。这套流程跑下来你得到的不仅是一张词云图而是一个可交互、可验证的人物关系分析框架。我自己的习惯是每次调整窗口大小或阈值后都把网络图存一份带时间戳的版本方便回溯对比。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

端侧AI助手实测:离线运行与端云协同的架构与避坑

端侧AI助手实测:离线运行与端云协同的架构与避坑

这几个月我一直在关注端侧大模型的应用进展,陆陆续续试过不少离线推理方案,但大部分都停留在“能跑通demo”的阶段,离真正能日常使用还有明显距离。所以当某家头部厂商公开测试一款把入口放在国民级社交应用里的本地AI助手时,我第…

2026/10/13 23:03:45 阅读更多 →
疯狂的“龙虾”接入TaoToken:究竟是“数字员工”还是“电子河豚”?

疯狂的“龙虾”接入TaoToken:究竟是“数字员工”还是“电子河豚”?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 23:03:45 阅读更多 →
蓝湖 MCP 快速上手手册(Claude + Codex):把 MCP endpoint 改到 TaoToken

蓝湖 MCP 快速上手手册(Claude + Codex):把 MCP endpoint 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 20:38:18 阅读更多 →

最新新闻

第6章:Spring AI 2.0 ChatClient 门面

第6章:Spring AI 2.0 ChatClient 门面

上章思考题答案 用户原话里的 {orderId} 若放进 SystemPromptTemplate 再渲染,StringTemplate 会把它当成变量。缺这个键时,ValidationMode.THROW 抛 IllegalStateException,正常咨询被拒绝。用户原话应走 UserMessage 或 ChatClient.user&a…

2026/10/14 0:03:43 阅读更多 →
【车载定位】基于扩展卡尔曼滤波 EKF,分别利用 TDOA、AOA 以及 TDOA+AOA 融合观测,搭配近恒速 NCV / 近恒位置 NCP运动模型对车辆轨迹估计附Matlab代码

【车载定位】基于扩展卡尔曼滤波 EKF,分别利用 TDOA、AOA 以及 TDOA+AOA 融合观测,搭配近恒速 NCV / 近恒位置 NCP运动模型对车辆轨迹估计附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和数学建模资料 &…

2026/10/14 0:03:43 阅读更多 →
人工智能期末复习:用习题集构建考点地图,高效备考不挂科

人工智能期末复习:用习题集构建考点地图,高效备考不挂科

简介:这份资源汇集人工智能课程各章小结与经典习题解答,适合正在系统学习人工智能基础、准备期末考试的本科生或自学者使用。内容覆盖人工智能的概念与发展阶段、研究学派与研究领域、知识与知识表示(谓词逻辑、产生式规则、框架、语义网络&a…

2026/10/14 0:03:43 阅读更多 →
wandb-core 中的 Wire 依赖注入:从贡献指南到 go:generate 自动装配实战

wandb-core 中的 Wire 依赖注入:从贡献指南到 go:generate 自动装配实战

机器学习深度学习数据可视化可观测性 【免费下载链接】wandb The AI developer platform. Use Weights & Biases to train and fine-tune models, and manage models from experimentation to production. 项目地址: https://gitcode.com/gh_mirrors/wa/wandb 点…

2026/10/14 0:03:43 阅读更多 →
微博评论文本情感分析:从数据清洗到三模型对比的完整实践

微博评论文本情感分析:从数据清洗到三模型对比的完整实践

简介:面向毕业设计场景,资源围绕微博评论文本情感分析,完整覆盖支持向量机、朴素贝叶斯与AdaBoost三种机器学习算法的建模流程,适合计算机相关专业本科生用于课程设计或毕业设计参考。压缩包共70个文件,约6.05MB&#…

2026/10/14 0:03:43 阅读更多 →
小型超市仓库管理系统

小型超市仓库管理系统

小型超市仓库管理系统选题背景与意义 随着我国城镇化进程的不断推进以及居民消费水平的持续提升,小型超市作为连接城市社区与消费者的重要商业节点,在日常生活中的作用日益凸显。尤其是在一二线城市周边的居民区、城乡结合部及中小城镇,小型超…

2026/10/14 0:02:42 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →