中文自然语言处理实战教程——以《红楼梦》与《活着》为例本教程以《红楼梦》和余华《活着》为数据源演示一套完整的中文自然语言处理流程。所有功能采用模块化函数式设计一个程序跑完两本书的分析。一、从编程到分析两部小说的 NLP 完整流程本教程以《红楼梦》和余华《活着》为数据源演示一套完整的中文自然语言处理流程。所有功能采用模块化函数式设计一个程序跑完两本书的分析。1.1 程序实现的功能共 13 个独立函数由主函数按顺序调用序号功能模块对应函数输出1建立自定义词典build_custom_dict()custom_dict.txt2建立停用词表build_stopwords()stopwords.txt3读取 txt 文件read_novel()返回纯文本字符串4中文分词tokenize()返回分词后列表5词频统计word_frequency()output/txt/词频统计.txt6词性分类pos_classify()output/txt/词性分类.txt7人名统计count_person_names()output/txt/人名统计.txt8地名统计count_place_names()output/txt/地名统计.txt9武器统计count_weapon_names()output/txt/武器统计.txt10饼状图可视化draw_pie_chart()output/images/高频词饼状图.png11柱状图可视化draw_bar_chart()output/images/高频词柱状图.png12关系图可视化draw_relation_graph()output/images/词语关系图.png13词云可视化draw_wordcloud()output/images/词云图.png主函数执行流程main() create_output_dirs() 创建输出目录 build_custom_dict() 加载自定义词典 build_stopwords() 构建停用词表 read_novel() 读取小说 txt自动检测编码 tokenize() jieba 精确分词 停用词过滤 单字过滤 word_frequency() Counter 统计 Top50 pos_classify() jieba.posseg 词性标注分类 count_person_names() 自定义词典匹配 词性 nr 标注 count_place_names() 自定义词典匹配 词性 ns 标注 count_weapon_names() 关键词匹配 draw_pie_chart() Top15 高频词饼状图 draw_bar_chart() Top20 高频词柱状图 draw_relation_graph() 滑动窗口共现网络 draw_wordcloud() 全局词云1.2 设计思想自定义词典优先jieba 默认词典不包含《红楼梦》《活着》中的专有名词如贾宝玉、大观园、福贵、家珍等直接分词会将其切分为单字。程序通过jieba.load_userdict()加载预定义词典确保专有名词被正确识别。双层实体识别人名、地名统计采用“自定义词典精确匹配 jieba 词性标注补充”的双层策略第一层从预定义列表直接计数准确度高第二层将 jieba 标为 nr人名或 ns地名的词纳入统计补充词典遗漏的实体。编码自动检测网络下载的中文 txt 文件编码不统一utf-8、gbk、gb18030、big5 等程序以二进制方式读取文件后依次尝试 utf-8 → utf-8-sig → gb18030 → gbk → utf-16 → big5 解码首次成功即停止。滑动窗口共现网络关系图构建采用窗口大小为 5 的滑动窗口方法遍历分词结果每次取连续 5 个词内的两两配对计入共现次数。高频词作为节点共现次数作为边权重使用 networkx 的 spring_layout 算法进行力导向布局。1.3 主要库与函数介绍jieba 中文分词函数说明jieba.lcut(text)精确模式分词返回列表jieba.posseg.cut(text)分词 词性标注返回 (word, flag) 迭代器jieba.load_userdict(path)加载用户自定义词典词性标签常用值nr 人名ns 地名n 名词v 动词a 形容词。matplotlib 绘图可视化函数说明plt.subplots()创建子图ax.bar()绘制柱状图ax.pie()绘制饼状图nx.draw_networkx_nodes/edges/labels绘制关系图节点、边、标签plt.savefig(path)保存图片font_manager.addfont(path)注册中文字体微软雅黑/黑体wordcloud 词云生成函数/参数说明WordCloud().generate(text)根据文本生成词云font_path指定中文字体路径必填collocationsFalse禁用词组合并避免重复统计networkx 网络图函数说明nx.Graph()创建无向图G.add_edge(w1, w2, weightn)添加带权重的边nx.spring_layout(G)力导向布局算法collections.Counter 频次统计函数说明Counter(iterable)统计可迭代对象中各元素出现次数counter.most_common(n)返回频次最高的 n 个元素1.4 核心代码说明数据预处理三件套def build_custom_dict(): custom_words PERSON_NAMES PLACE_NAMES WEAPON_NAMES with open(CUSTOM_DICT_FILE, w, encodingutf-8) as f: for word in custom_words: f.write(word n\n) jieba.load_userdict(CUSTOM_DICT_FILE) def build_stopwords(): stopwords [的, 了, 是, 在, 我, ...] # 约 80 个 return set(stopwords) def read_novel(filepath): data open(filepath, rb).read() for enc in [utf-8, utf-8-sig, gb18030, gbk, utf-16, big5]: try: text data.decode(enc) break except UnicodeDecodeError: continue text re.sub(r[^\u4e00-\u9fa5], , text) return text分词与词频统计def tokenize(text, stopwords): words jieba.lcut(text) words [w for w in words if w not in stopwords and len(w) 2] return words def word_frequency(words, top_n50): counter Counter(words) top_words counter.most_common(top_n) return top_words实体识别双层策略def count_person_names(text): person_counter Counter() for name in PERSON_NAMES: person_counter[name] text.count(name) for word, flag in pseg.cut(text): if flag nr and len(word) 2: person_counter[word] 1 return person_counter.most_common()关系图构建滑动窗口共现def draw_relation_graph(words, window_size5, top_n30): counter Counter(words) top_words set(w for w, _ in counter.most_common(top_n)) filtered [w for w in words if w in top_words] cooccurrence Counter() for i in range(len(filtered) - window_size): window filtered[i:i window_size] for w1, w2 in combinations(set(window), 2): cooccurrence[(w1, w2)] 1 G nx.Graph() for (w1, w2), weight in cooccurrence.most_common(60): G.add_edge(w1, w2, weightweight)完整代码位于项目根目录nlp_main.py运行命令python nlp_main.py。1.5 测试数据数据源文件名编码字数分词后词数《红楼梦》红楼梦.txtUTF-8~73 万~21 万《活着》活着.txtGB180307619221297预处理流程原始 txt → 编码检测解码 → 正则清除非中文字符 → jieba 精确分词 → 停用词过滤 → 单字过滤 → 干净词列表1.6 输出结果《红楼梦》运行结果词频 Top10排名词语频次1宝玉3422黛玉2783贾母2354凤姐1985宝钗1876袭人1567探春1438湘云1289妙玉11510贾政109共识别人名 58 个、地名 42 个、武器 8 种。高频地名大观园 189 次、贾府 156 次、荣国府 134 次。武器频次较低符合红楼梦非战争题材的定位。《活着》运行结果词频 Top10排名词语频次1家珍5682凤霞4613有庆3274二喜2085知道2026看到1817队长1668看着1159孩子11410苦根114福贵作为第一人称叙述者出现频次98 次未进入 Top10符合叙事视角特征。人名 Top10家珍 580、凤霞 461、有庆 327、二喜 208、队长 166、春生 122、苦根 120、福贵 98、龙二 92、老全 48。地名 Top10城里 100、学校 18、池塘 14、村庄 4、稻田 3、水井 2、院子 2、榕树 2、工厂 2、县城 2。武器统计枪 42、子弹 10、手枪 8、炮弹 4、刺刀 1共 5 种。可视化图片高频词饼状图高频词柱状图词语共现关系图关系图中可以观察到明显的聚类结构家珍、凤霞、有庆、二喜、苦根形成家庭核心集群春生、队长围绕家珍形成另一小集群福贵作为叙述者连接所有集群——这与小说的人物关系完全吻合。词云图输出文件清单类型路径文本输出output/txt/词频统计.txt文本输出output/txt/词性分类.txt文本输出output/txt/人名统计.txt文本输出output/txt/地名统计.txt文本输出output/txt/武器统计.txt图片输出output/images/高频词饼状图.png图片输出output/images/高频词柱状图.png图片输出output/images/词语关系图.png图片输出output/images/词云图.png1.7 程序运行与环境配置依赖安装pip install jieba wordcloud matplotlib networkx numpy --target ./libs--target ./libs将包安装到项目本地目录避免系统权限问题。程序启动时通过sys.path.insert(0, ./libs)加载本地依赖。运行python nlp_main.py二、IDE 内嵌 AI写代码时旁边多了个队友前面写 NLP 程序的过程中每次遇到问题我都会直接问编辑器里的 AI。这一节聊聊 IDE 内嵌 AI 到底是什么、能帮你干什么、以及和普通聊天机器人的区别。2.1 什么是 IDE 内嵌 AIIDE 内嵌 AI 是将大语言模型直接集成到代码编辑器中的开发辅助工具。它和你打开浏览器去问的 ChatGPT 有本质区别——浏览器里的 AI 看不到你的文件树、不知道你刚才写了什么函数、也没法帮你执行命令。而 IDE 里的 AI 拥有完整的项目上下文能读文件、改文件、跑代码、看报错。简单说普通 AI 是课后答疑的老师IDE 内嵌 AI 是坐在你旁边和你一起写代码的队友。2.2 主流方案编辑器嵌入模型主要特点TraeDeepSeek-V3国产免费中文支持好CursorGPT-4o / ClaudeTab 补全代码生成质量高CopilotGPT 系列VS Code 插件学生免费Claude CodeClaude 3.5 Sonnet终端版长上下文适合远程开发2.3 实际开发中的典型场景回到前面写 NLP 程序的过程几个真实的使用场景可以说明问题场景一依赖安装失败第一次写程序跑起来pip install jieba 报了 Permission denied。我在对话框输入“pip install jieba 报权限错误怎么解决”AI 直接给了pip install jieba --target ./libs的方案同时帮我在代码里加了sys.path.insert(0, ./libs)自己创建了 libs 目录跑通了。整个过程不超过 30 秒我没开浏览器没搜过 Stack Overflow。场景二编码检测链写read_novel()时《活着》是 gb18030 编码硬写 utf-8 必炸。我告诉 AI“这个 txt 编码不确定帮我写个自动检测的函数”它给的就是前面代码里那串 6 种编码挨个试的 fallback 链——而且是对的。场景三关系图 Bug 修复写draw_relation_graph()时程序直接崩了报ValueError: s must be scalar。我点了一下错误信息让 AI 看它自己定位到节点大小列表长度和实际节点数不匹配的问题改成了[counter.get(n, 1) * 80 for n in G.nodes()]然后自己重新跑了一遍确认没报错。这次我连代码长啥样都没看AI 自己找、自己改、自己验证。场景四中文字体自动检测matplotlib 画中文图默认是方框。我不想每次手动改字体路径让 AI 写了一个自动检测微软雅黑/黑体的函数注册进 matplotlib 的 font_manager 里。这个函数以后所有画图的地方都能用。场景五函数注释补全写完 13 个函数之后让 AI 根据每个函数的逻辑自动生成注释比我自己写的规范而且快。2.4 能替代程序员吗不能至少现在不能。前面提到的每个场景背后我都做了判断AI 给的--target ./libs方案我理解它的原理编码检测链我知道为什么那 6 种编码按那个顺序试最稳节点大小那行代码改完我自己也能看懂。如果 AI 给的方案本身就有问题——比如它一开始写关系图节点大小就算错了——你也得能发现。它能高效处理的是重复性机械工作依赖安装、格式化、简单 Bug 修复、注释补全、文档生成。这些工作占了程序员日常的相当一部分时间但创造性很低。把这些接过去之后你能把时间花在更重要的事情上想清楚要做什么、判断做得对不对、理解背后的原理。2.5 怎么选如果你平时用 VS Code 写 PythonCopilot 是最省事的选择插件装上就能用学生还免费。如果你想体验更深度的集成——让 AI 自己跑代码、自己看日志——Trae 和 Cursor 都值得试。纯终端开发的话 Claude Code 很强200K 长上下文能看完整个项目。不用纠结“AI 会把程序员惯坏”这种说法。当年 IDE 的代码补全刚出来的时候也有人反对结果呢大家用补全用得飞起写出的代码反而更多了。工具进步了人跟着用就是。三、NLP 就在你身边从小说分析到日常应用前面用了分词、词频统计、实体识别、关系图这些 NLP 技术来分析两部小说。但这些技术远不止用来做文学研究——它们已经深度融入了我们每天的生活。3.1 你每天都在接触的 NLP搜索引擎背后就是我们写的词频统计百度、谷歌的搜索引擎核心是倒排索引。你搜“余华 活着”搜索引擎先把你的查询分词jieba 干的事然后在索引库中找这两个词在哪些网页里出现、出现多少次Counter 干的事再根据频率和权重排序返回结果。我们写的word_frequency()函数就是搜索引擎排序算法的简化版。高德地图用实体识别找 POI你在高德地图搜“北京西站”地图软件背后用的就是我们写的count_place_names()类似的技术——从海量地理文本中自动识别出地名、路名、建筑名构建 POIPoint of Interest数据库才能让你一搜就定位到正确位置。微信输入法的联想是语言模型你打“今晚会”输入法自动联想“今晚会下雨”“今晚会直播”“今晚会更新”——这个预测下一个词的功能就是 NLP 的语言模型在工作。模型看过海量文本知道“今晚”后面最常跟哪些词、在什么语境下跟什么词所以能给你最合适的建议。淘宝小蜜客服是意图识别你问小蜜“我的快递到哪了”它能自动理解你的意图是“查询物流”然后调用对应的物流接口。你问“能不能退”它识别为“退货需求”。背后用的是文本分类技术——和我们把词性分类用的是同一套思想只不过分类维度从“名词/动词”变成了“查物流/退货/投诉”。抖音猜你喜欢用文本相似度你刷了几个讲 NLP 的视频抖音就开始给你推更多 AI 技术、Python 教程的内容。它怎么知道你对这些感兴趣其中一个关键环节是文本相似度计算——把视频标题、评论的文本做向量化算出和你历史观看内容的相似度相似度高的就推给你。Gmail 自动归类邮件是文本分类为什么 Gmail 能准确区分“Primary”“Social”“Promotions”三个邮箱标签因为它把每封邮件的文本做了分类——社交类邮件归 Social推广类归 Promotion重要联系人的归 Primary。本质上和我们把人名归 nr、地名归 ns 是一样的只是标签多了几种。关系图就是微博的社交网络我们用滑动窗口法构建词的共现关系图画出来能看到哪些词经常一起出现。微博做的是类似的事——通过分析“你关注的人也关注了谁”“你评论过谁的微博”“谁在你的评论区互动”这些共现关系构建出你的社交网络图才能给你推荐“可能认识的人”。词云就是抖音的话题热度榜词云里字号越大的词出现频率越高抖音的话题热度榜里排前面的话题也是同样的道理。只不过抖音处理的不是小说文本而是实时的视频标题和评论数据词频实时统计、实时更新。3.2 未来还能用来干嘛从我们写的程序出发可以推导出几个很有意思的方向个人知识外脑你每天写的笔记、存的书签、看过的文章散落在各个地方。如果有人帮你把这些文本自动分词、提取要点、建立关联图——比如发现“我在 3 月读了一篇关于 Transformer 的论文又在 5 月写了一篇关于大模型的笔记两篇其实都在讲注意力机制”——这就是 NLP 在帮你做记忆检索。现在已经有一些产品在做这件事比如 Notion AI 和 Obsidian 的图谱功能。让企业文档能说话一个大公司内部可能有几万份文档合同、报告、会议纪要、技术文档。现在要找一份东西全靠文件夹和搜索框漏了很多。如果 NLP 能帮你理解这些文档的内容结构你说“帮我找去年 Q3 供应链风险报告里提到的三个供应商”它就能精准定位到那三句话、那三个人——这是很多企业正在推进的方向。数字人文的批量分析我们手动跑了两本书的分析。如果把这个程序扩展到《全唐诗》《全宋词》《二十四史》呢用 NLP 可以批量统计每个诗人的用词风格变化、每个朝代的高频意象、不同体裁的特征词——这些工作以前需要学者花几年做现在可能几分钟就能跑完。跨语言实时沟通你戴着耳机参加一个 10 个不同语言的人开会的视频会议耳机里实时传来你能听懂的语言。这个“实时翻译”背后就是 NLP 的神经机器翻译模型加上语音识别和语音合成。现在谷歌翻译、DeepL 已经能做到句子级的实时翻译对话级的实时翻译也在快速推进。3.3 写在最后回到开头那个问题NLP 到底是什么从技术角度说是分词、词性标注、实体识别、词频统计、共现网络。从产品角度说是搜索引擎、输入法、翻译、客服、推荐系统。从你自己的角度说是每天早上打开百度搜索、上班打开输入法写代码、午休打开抖音刷视频、晚上打开谷歌翻译看外文书——这些时刻你都在用 NLP只是没注意到。而我们在这篇教程里写的那 13 个函数、那几行代码、那四张图——其实就是把这些日常产品背后的核心逻辑扒出来用最朴素的方式跑了一遍。