☰
自然语言处理作业
2026/11/1 1:57:51 网站建设 项目流程

中文自然语言处理实战教程——以《红楼梦》与《活着》为例

本教程以《红楼梦》和余华《活着》为数据源,演示一套完整的中文自然语言处理流程。所有功能采用模块化函数式设计,一个程序跑完两本书的分析。


一、从编程到分析:两部小说的 NLP 完整流程

本教程以《红楼梦》和余华《活着》为数据源,演示一套完整的中文自然语言处理流程。所有功能采用模块化函数式设计,一个程序跑完两本书的分析。


1.1 程序实现的功能

共 13 个独立函数,由主函数按顺序调用:

序号功能模块对应函数输出
1建立自定义词典build_custom_dict()custom_dict.txt
2建立停用词表build_stopwords()stopwords.txt
3读取 txt 文件read_novel()返回纯文本字符串
4中文分词tokenize()返回分词后列表
5词频统计word_frequency()output/txt/词频统计.txt
6词性分类pos_classify()output/txt/词性分类.txt
7人名统计count_person_names()output/txt/人名统计.txt
8地名统计count_place_names()output/txt/地名统计.txt
9武器统计count_weapon_names()output/txt/武器统计.txt
10饼状图可视化draw_pie_chart()output/images/高频词饼状图.png
11柱状图可视化draw_bar_chart()output/images/高频词柱状图.png
12关系图可视化draw_relation_graph()output/images/词语关系图.png
13词云可视化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指定中文字体路径(必填)
collocations=False禁用词组合并,避免重复统计

networkx 网络图

函数说明
nx.Graph()创建无向图
G.add_edge(w1, w2, weight=n)添加带权重的边
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", encoding="utf-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_n=50): 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_size=5, top_n=30): 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, weight=weight)

完整代码位于项目根目录nlp_main.py,运行命令:python nlp_main.py。


1.5 测试数据

数据源文件名编码字数分词后词数
《红楼梦》红楼梦.txtUTF-8~73 万~21 万
《活着》活着.txtGB180307619221297

预处理流程:

原始 txt → 编码检测解码 → 正则清除非中文字符 → jieba 精确分词 → 停用词过滤 → 单字过滤 → 干净词列表

1.6 输出结果

《红楼梦》运行结果

词频 Top10:

排名词语频次
1宝玉342
2黛玉278
3贾母235
4凤姐198
5宝钗187
6袭人156
7探春143
8湘云128
9妙玉115
10贾政109

共识别人名 58 个、地名 42 个、武器 8 种。高频地名:大观园 189 次、贾府 156 次、荣国府 134 次。武器频次较低,符合红楼梦非战争题材的定位。

《活着》运行结果

词频 Top10:

排名词语频次
1家珍568
2凤霞461
3有庆327
4二喜208
5知道202
6看到181
7队长166
8看着115
9孩子114
10苦根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/词云图.png

1.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 内嵌 AI

IDE 内嵌 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 写 Python,Copilot 是最省事的选择,插件装上就能用,学生还免费。如果你想体验更深度的集成——让 AI 自己跑代码、自己看日志——Trae 和 Cursor 都值得试。纯终端开发的话 Claude Code 很强,200K 长上下文能看完整个项目。

不用纠结“AI 会把程序员惯坏”这种说法。当年 IDE 的代码补全刚出来的时候也有人反对,结果呢?大家用补全用得飞起,写出的代码反而更多了。工具进步了,人跟着用就是。


三、NLP 就在你身边:从小说分析到日常应用

前面用了分词、词频统计、实体识别、关系图这些 NLP 技术来分析两部小说。但这些技术远不止用来做文学研究——它们已经深度融入了我们每天的生活。


3.1 你每天都在接触的 NLP

搜索引擎背后就是我们写的词频统计

百度、谷歌的搜索引擎,核心是倒排索引。你搜“余华 活着”,搜索引擎先把你的查询分词(jieba 干的事),然后在索引库中找这两个词在哪些网页里出现、出现多少次(Counter 干的事),再根据频率和权重排序返回结果。我们写的word_frequency()函数,就是搜索引擎排序算法的简化版。

高德地图用实体识别找 POI

你在高德地图搜“北京西站”,地图软件背后用的就是我们写的count_place_names()类似的技术——从海量地理文本中自动识别出地名、路名、建筑名,构建 POI(Point 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 个函数、那几行代码、那四张图——其实就是把这些日常产品背后的核心逻辑扒出来,用最朴素的方式跑了一遍。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询