Python词云实战:从《红楼梦》文本分析到可视化呈现
2026/7/31 7:52:04 网站建设 项目流程

1. 从《红楼梦》到词云:一个数据爱好者的文本探索之旅

最近在整理书架,又看到了那本厚厚的《红楼梦》。作为一个常年和数据打交道的程序员,我忽然冒出一个念头:这部百万字的文学巨著,如果用数据视角来看,会呈现出怎样一幅图景?哪些人物被提及最多?哪些情感词汇贯穿始终?与其凭空想象,不如动手写个程序来一探究竟。用Python来做文本分析和词频统计,再生成一张直观的词云图,听起来就是个既有趣又有成就感的周末小项目。

这个想法其实源于很多朋友常问的一个问题:“学了Python基础语法后,能做什么有意思的实战项目?” 词频统计和词云生成就是一个绝佳的答案。它串联起了文件操作、字符串处理、字典统计、第三方库使用和数据可视化等多个核心知识点,而且结果直观有趣,成就感满满。无论是分析小说、社媒文本还是工作报告,这套方法都通用。今天,我就以《红楼梦》为例,手把手带你走完从零开始,到最终生成专属词云图的完整流程。你会发现,用代码阅读经典,别有一番风味。

2. 项目核心思路与工具选型:为什么是它们?

在动手写代码之前,我们先花点时间理清整个项目的逻辑链条,并搞清楚每个环节为什么要选择特定的工具或库。盲目堆砌代码是新手常犯的错,理解背后的“为什么”才能举一反三。

2.1 数据处理流程拆解

整个项目可以清晰地分为四个阶段:获取文本 -> 清洗整理 -> 统计词频 -> 可视化呈现

  1. 获取文本:我们需要一份《红楼梦》的纯文本文件(.txt格式)。这是分析的原材料。你可以从古登堡计划等公开领域书籍网站下载,确保编码是UTF-8,避免后续乱码问题。
  2. 清洗整理:原始文本包含大量对词频统计无意义的“噪音”,比如标点符号、空格、换行符,以及“的”、“了”、“在”这类极高频但无实义的“停用词”。这一步的目标是得到一份“干净”的词语列表。
  3. 统计词频:遍历清洗后的词语列表,计算每个词出现的次数。Python的字典(dict)数据结构是完成这个任务的绝佳工具,它以“词”为键(key),“出现次数”为值(value)。
  4. 可视化呈现:将统计好的词频数据,传递给词云生成库,它会根据词频高低,自动生成一张布局美观、大小不一的词云图。高频词会显得更大、更突出。

2.2 关键工具库的选择与理由

这里会用到几个Python第三方库,我们逐一说明选择它们的原因和备选方案。

  • jieba:中文分词利器

    • 为什么是它?英文文本有天然的空格分隔单词,但中文句子是连续的字符串。例如,“贾宝玉走进怡红院”需要被切分成“贾宝玉”、“走进”、“怡红院”这样的独立词语,这个过程就叫“分词”。jieba库是Python中最流行、最成熟的中文分词工具,准确率高,使用简单。
    • 核心原理:它基于统计模型和词典,识别句子中最可能的词语组合。我们只需要调用jieba.lcut(text),就能得到分词后的列表。
    • 备选:对于现代网络用语,pkuseg等可能在某些领域更准,但对于古典文学,jieba的通用性完全足够。
  • wordcloud:词云生成的核心

    • 为什么是它?这是Python生态中专为生成词云图设计的库。它不仅能根据词频调整字体大小,还支持自定义形状(比如把词云填充在一个中国地图的轮廓里)、颜色方案、背景遮罩等高级功能。
    • 核心原理:它通过一个简单的WordCloud().generate_from_frequencies(freq_dict)接口,接收我们统计好的词频字典,自动完成布局、渲染和生成图像的所有复杂计算。
    • 注意wordcloud库默认可能不包含中文字体,需要额外指定一个中文字体文件(.ttf)路径,否则生成的词云会是乱码(小方框)。
  • matplotlib/PIL:图像显示与处理

    • matplotlib:是Python数据可视化的基石。我们主要用它来创建画布、显示和保存由wordcloud生成的图像。plt.imshow()plt.axis('off')是常用组合。
    • PIL(Pillow库):一个强大的图像处理库。在更进阶的词云玩法中,如果你需要将词云填充到一个自定义形状(如宝黛的剪影)里,就需要用PIL来读取和处理那张形状图片,将其作为遮罩(mask)传递给wordcloud
  • collections.Counter:可选的统计增强工具

    • 这是一个内置模块,提供了比手动操作字典更便捷的计数功能。Counter(词语列表)可以直接返回一个类似字典的计数对象,并且有most_common(n)方法能直接输出前N个最高频的词,非常方便。我们会在代码中展示两种方法。

提示:安装这些库非常简单,在命令行中使用pip install jieba wordcloud pillow matplotlib即可一键完成。如果下载慢,可以临时使用国内镜像源,例如pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba wordcloud pillow matplotlib

3. 实战第一步:环境准备与文本预处理

理论清晰了,现在打开你的代码编辑器(VSCode、PyCharm甚至记事本都行),我们开始写代码。第一步是搭建好工作环境并处理好原始文本。

3.1 创建项目与导入库

首先,在一个单独的文件夹里创建一个Python脚本文件,比如叫dream_of_red_mansion_wordcloud.py。然后在文件开头,导入我们需要的所有库。

# -*- coding: utf-8 -*- import jieba # 中文分词 from wordcloud import WordCloud # 生成词云 import matplotlib.pyplot as plt # 绘图展示 from collections import Counter # 词频计数(可选,方便) import re # 正则表达式,用于文本清洗 # 如果要用自定义形状,还需要 from PIL import Image

第一行的# -*- coding: utf-8 -*-是为了确保Python解释器能正确识别文件中的中文字符,这是一个好习惯。

3.2 读取文本与编码处理

将下载好的《红楼梦》txt文件(假设命名为hongloumeng.txt)放在与脚本相同的目录下,然后读取它。

# 读取《红楼梦》全文 file_path = 'hongloumeng.txt' try: with open(file_path, 'r', encoding='utf-8') as f: text = f.read() except FileNotFoundError: print(f"错误:未找到文件 {file_path},请检查文件路径和名称。") exit() except UnicodeDecodeError: # 如果utf-8失败,尝试其他常见编码,如gbk try: with open(file_path, 'r', encoding='gbk') as f: text = f.read() except UnicodeDecodeError: print("错误:文件编码无法识别,请确保文件为UTF-8或GBK编码。") exit()

这里使用了try...except结构进行健壮性处理。因为从网络下载的文本编码可能是UTF-8GBK,这段代码能自动尝试,避免程序因编码问题直接崩溃。with open(...) as f:的写法能确保文件被正确关闭。

3.3 文本清洗:去除噪音与停用词

现在text变量里是完整的《红楼梦》文本。直接对它分词效果会很差,因为包含了大量干扰项。

第一步:去除标点、数字和特殊字符。我们可以使用正则表达式re.sub(),只保留中文汉字、以及可能的人名中的点(如“林黛玉·潇湘妃子”中的点,但《红楼梦》中较少)。

# 使用正则表达式移除所有非中文字符(保留汉字) # 这个模式匹配任何非中文字符,并将其替换为空字符串 pattern = re.compile(r'[^\u4e00-\u9fa5]') # \u4e00-\u9fa5 是Unicode中汉字的大致范围 cleaned_text = pattern.sub('', text)

第二步:加载停用词表。停用词是指在各种文本中都频繁出现,但对分析主题没有贡献的词,如“的”、“了”、“和”、“在”等。我们需要一个停用词列表来过滤它们。你可以从网上下载一个通用的中文停用词表(如hit_stopwords.txtcn_stopwords.txt),也可以自己根据《红楼梦》的特点补充(比如“说道”、“一面”、“只见”等叙述性词语)。

# 假设你有一个停用词文件 stopwords.txt,每行一个词 stopwords_path = 'stopwords.txt' stopwords = set() try: with open(stopwords_path, 'r', encoding='utf-8') as f: for line in f: word = line.strip() if word: stopwords.add(word) except FileNotFoundError: print(f"警告:未找到停用词文件 {stopwords_path},将仅使用内置停用词。") # 可以在这里添加一些最基本的停用词 stopwords.update(['的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这', '那', '她', '他', '我们'])

这里使用set()集合来存储停用词,因为集合的查找速度远快于列表,当我们需要判断一个词是否在停用词表中时,效率更高。

4. 核心环节:中文分词与词频统计

文本清洗干净后,就进入了最核心的分析阶段:把连续的字符串变成有意义的词语,并数一数它们各出现了多少次。

4.1 使用jieba进行精确分词

jieba库提供了几种分词模式,对于词频统计,我们通常使用精确模式,它试图将句子最精确地切开,适合文本分析。

# 使用jieba进行精确模式分词 words = jieba.lcut(cleaned_text) # lcut 返回一个列表(list) print(f"分词完成,共得到 {len(words)} 个词语。")

jieba.lcut()函数返回一个词语列表。例如,“贾宝玉走进怡红院”会被切分成['贾宝玉', '走进', '怡红院']

4.2 过滤停用词与单字词

分词后的列表里,仍然包含停用词和一些无意义的单字词(在中文里,很多单字不成词,如“时”、“事”,但像“黛”、“玉”作为人名一部分被切出,有时也需要根据情况处理)。我们需要过滤它们。

# 过滤停用词和长度小于2的词语(通常单字词意义不大,但可根据需求调整) filtered_words = [] for word in words: if word not in stopwords and len(word) > 1: # 保留长度大于1的词 filtered_words.append(word) print(f"过滤后,剩余 {len(filtered_words)} 个有效词语。")

这里我选择过滤掉长度小于等于1的词,这能有效去除大部分无意义的单字碎片。但请注意,像“黛”、“玉”这样的字如果被单独切出,也会被过滤掉。对于《红楼梦》的人名分析,这有时可能造成遗漏。更精细的做法是结合jieba自定义词典功能,将主要人物名称(如“贾宝玉”、“林黛玉”、“薛宝钗”、“王熙凤”)加入词典,确保它们被作为一个整体切分出来,不被过滤。

4.3 两种词频统计方法对比

得到干净的词语列表后,就可以开始计数了。这里介绍两种方法。

方法一:使用Python原生字典(手动统计)这是最基础、最能理解原理的方法。

# 方法一:使用字典手动统计 word_freq = {} for word in filtered_words: word_freq[word] = word_freq.get(word, 0) + 1 # get(word, 0) 方法:如果字典里有word这个键,返回其值;如果没有,返回0。

方法二:使用collections.Counter这是更Pythonic、更高效的方法,尤其适合需要获取最高频词汇的场景。

# 方法二:使用Counter word_counter = Counter(filtered_words) # 获取出现频率最高的20个词 top_20_words = word_counter.most_common(20) print("出现频率最高的20个词语:") for word, freq in top_20_words: print(f"{word}: {freq}")

运行到这里,你应该能在控制台看到《红楼梦》里最高频的词语了。不出意外的话,“宝玉”、“黛玉”、“贾母”、“凤姐”、“夫人”、“姑娘”等人物称谓会名列前茅,“笑道”、“听见”、“回来”、“如今”等叙述性词语也会高频出现。这个列表本身就已经能揭示很多文本特征了。

5. 生成与美化词云图

统计结果有了,最后一步就是将其视觉化。我们将使用wordcloud库,并解决生成过程中最关键的中文显示问题。

5.1 配置WordCloud并生成基础词云

生成词云的核心是创建一个WordCloud对象,并传入必要的参数。

# 准备词频数据,WordCloud需要的是一个字典 {‘词’: 频率} # 如果使用方法二的Counter,可以直接传入 word_counter # 如果使用方法一的字典,就直接传入 word_freq freq_for_wordcloud = dict(word_counter) # 将Counter对象转为普通字典,或直接用word_freq # 配置词云参数 wc = WordCloud( font_path='simhei.ttf', # *关键*:指定中文字体路径,否则乱码 width=800, # 图片宽度 height=600, # 图片高度 background_color='white', # 背景色 max_words=200, # 最多显示词数 max_font_size=150, # 最大字体大小 min_font_size=10, # 最小字体大小 random_state=42, # 随机种子,保证每次生成布局一致 collocations=False, # 是否包含两个词的搭配(二元词组),设为False避免“宝玉说”这类组合 ) # 根据词频生成词云 wc.generate_from_frequencies(freq_for_wordcloud)

关键参数详解:

  • font_path:这是解决中文显示问题的核心!你必须指定一个系统中文字体文件的路径。simhei.ttf(黑体)是Windows常见字体。你也可以用msyh.ttc(微软雅黑)或下载其他喜欢的字体。务必确保这个路径正确。可以将字体文件放在项目目录下,直接写文件名;或者写绝对路径,如C:/Windows/Fonts/simhei.ttf
  • collocations=False:这个参数很重要。默认情况下,wordcloud会考虑词语的共现关系(搭配),这可能导致像“宝玉笑道”这样的短语被当做一个整体,影响单个词的统计。设为False后,词云将严格基于我们传入的单个词语的频率生成。

5.2 显示与保存词云图

生成wc对象后,我们用matplotlib来展示和保存它。

# 使用matplotlib显示图片 plt.figure(figsize=(10, 8)) # 设置画布大小 plt.imshow(wc, interpolation='bilinear') # 显示词云, interpolation使图像更平滑 plt.axis('off') # 关闭坐标轴 plt.title('《红楼梦》词云图', fontsize=16) # 添加标题 plt.tight_layout(pad=0) # 调整布局,使图片填充整个区域 plt.show() # 保存词云图片到文件 output_path = 'hongloumeng_wordcloud.png' wc.to_file(output_path) print(f"词云图已保存至:{output_path}")

运行这段代码,一个黑白配色的基础词云图就会弹窗显示,并保存为hongloumeng_wordcloud.png。你会看到“宝玉”、“黛玉”等词以巨大的字体位于中央。

5.3 进阶美化:自定义形状与颜色

基础词云略显单调。我们可以让它变得更有趣,比如把词云填充在一个“中国印”或者“红楼梦”书法的形状里。

第一步:准备形状遮罩图片。你需要一张背景为白色、形状为黑色的PNG图片(轮廓清晰为佳)。例如,一个红色的中国印章图片,将其处理成白底黑印的形状。

第二步:使用PIL读取并处理遮罩图片。

from PIL import Image import numpy as np # 读取形状图片,并将其转换为灰度数组作为遮罩 mask_image = np.array(Image.open("chinese_seal_mask.png")) # 替换为你的形状图片路径 # 遮罩图片中,白色部分(255)将被视为背景(不填充词),黑色部分(0)将被填充。 # WordCloud期望遮罩中非白色的区域是形状区域。

第三步:在WordCloud参数中启用遮罩和颜色方案。

wc_advanced = WordCloud( font_path='simhei.ttf', width=800, height=600, background_color='white', max_words=300, mask=mask_image, # 指定遮罩 contour_width=1, # 轮廓线宽度 contour_color='steelblue', # 轮廓线颜色 colormap='viridis', # 使用matplotlib的配色方案,如 'viridis', 'plasma', 'inferno', 'magma', 'cividis' collocations=False, random_state=42, ) wc_advanced.generate_from_frequencies(freq_for_wordcloud) # 显示和保存 plt.figure(figsize=(12, 10)) plt.imshow(wc_advanced, interpolation='bilinear') plt.axis('off') plt.title('《红楼梦》- 自定义形状词云', fontsize=18) plt.tight_layout(pad=0) plt.show() wc_advanced.to_file('hongloumeng_wordcloud_shaped.png')

colormap参数提供了丰富的颜色主题,你可以尝试不同的值,找到最符合《红楼梦》古典韵味的配色。

6. 踩坑实录与性能优化心得

在实际操作中,你几乎一定会遇到下面这几个问题。我把我的踩坑经验和解决方案分享给你,能帮你节省大量时间。

6.1 中文乱码问题:字体路径的终极解决方案

这是新手遇到最多的问题,生成的词云全是方框。解决方案绝对不止“设置font_path”那么简单。

  • 问题根源wordcloud底层使用PIL/Pillow库绘图,默认字体不支持中文。
  • 解决方案
    1. 绝对路径最可靠:不要只用‘simhei.ttf’,如果字体不在当前目录或系统标准字体目录,就会失败。使用绝对路径:font_path=‘C:/Windows/Fonts/simhei.ttf’(Windows)或font_path=‘/System/Library/Fonts/PingFang.ttc’(macOS)。
    2. 字体文件确认:去对应路径下确认字体文件确实存在。注意.ttc(字体集合)和.ttf(单个字体)的区别,大部分情况下两者都支持。
    3. 备用字体方案:在代码中加入判断,如果首选字体失败,尝试备用字体。
      import os font_candidates = [ 'C:/Windows/Fonts/simhei.ttf', 'C:/Windows/Fonts/msyh.ttc', '/System/Library/Fonts/PingFang.ttc', '/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf', # Linux 'simhei.ttf' # 当前目录 ] font_path = None for candidate in font_candidates: if os.path.exists(candidate): font_path = candidate break if font_path is None: print(“错误:未找到可用的中文字体文件,请手动指定。”) exit()

6.2 分词不准确与自定义词典

对于《红楼梦》,很多人名、地名是特定词汇,jieba的默认词典可能切分不准。例如,“贾宝玉”可能被切成“贾宝”和“玉”。

  • 解决方案:使用jieba.load_userdict()加载自定义词典。
    1. 创建一个文本文件,比如custom_dict.txt,每行一个词,可以包含词频和词性(可省略),格式如:贾宝玉 3 nr(nr代表人名)。
    2. 在分词前加载它:jieba.load_userdict(‘custom_dict.txt’)
    3. 将《红楼梦》中的主要人物、关键地点(如“怡红院”、“潇湘馆”、“大观园”)都加入词典,能极大提升分词准确性,让词频统计更有意义。

6.3 停用词表需要“因地制宜”

通用停用词表能过滤“的”、“了”,但《红楼梦》有其独特的语言风格。像“说道”、“一面”、“只见”、“却说”、“如今”、“所以”等词,在小说中频率极高,但对分析人物、主题帮助不大,反而会挤占词云空间。

  • 实操建议:先运行一次基础统计,查看高频词列表。将那些明显属于叙述性、功能性的高频词(非实体名词、动词)加入到你的停用词表中。这是一个迭代的过程,反复清洗几次后,得到的词云会更聚焦于核心内容。

6.4 处理大文本时的性能问题

《红楼梦》全文约百万字,处理起来尚可。但如果分析更庞大的文本(如全唐诗、新闻语料库),性能可能成为瓶颈。

  • 优化技巧
    1. 分块读取与处理:对于超大文件,不要一次性read()到内存。可以按行或按大小分块读取、清洗、分词,并即时更新Counter对象。
    2. 使用生成器jieba.cut返回的是一个生成器,相比jieba.lcut(返回列表)更节省内存,适合流式处理。
    3. 谨慎使用most_common():如果只需要前N个词,Countermost_common(N)方法非常高效。但如果需要完整的排序列表,对于极大的词典,排序操作(sorted(word_freq.items(), key=lambda x: x[1], reverse=True))会消耗较多时间和内存。

7. 从词云到洞察:如何解读你的分析结果

生成了漂亮的词云图,项目就结束了吗?不,这恰恰是数据分析的开始。词云是一种快速呈现的“摘要”,而真正的价值在于对高频词背后的含义进行解读。

1. 人物关系与核心地位分析:“宝玉”、“黛玉”、“宝钗”、“凤姐”、“贾母”占据中心,这直观印证了他们在故事中的核心地位。你可以进一步统计两两人物名字在同一回目或段落中共同出现的频率,用网络图来可视化人物关系,这比词云又进了一步。

2. 情感色彩与主题挖掘:除了人名,高频的动词和形容词也值得关注。例如,统计“笑”、“哭”、“怒”、“叹”等情感词的出现频率和分布章节,可以量化分析小说的情感起伏。再比如,“梦”、“幻”、“空”、“情”这些字眼的高频出现,正是《红楼梦》哲学主题的体现。

3. 对比分析:你可以将前80回和后40回(通常认为作者不同)分别进行词频统计和词云生成,然后对比高频词的变化。这或许能从数据角度为一些文学考据提供有趣的侧面参考。

4. 技术扩展:

  • 词性标注:使用jieba.posseg进行词性标注,然后分别统计名词、动词、形容词的词频,可以得到更结构化的洞察。
  • 上下文分析(N-gram):统计二元词组(如“宝玉笑道”、“黛玉葬花”)或三元词组的频率,能发现固定的短语搭配和经典场景。
  • 时序分析:以“回”为单位,分析某个特定词汇(如“科举”、“功名”)出现频率的变化曲线,观察其叙事线索。

这个项目虽然始于一个简单的词频统计,但它像一扇门,背后连接着自然语言处理(NLP)和文本数据挖掘的广阔天地。当你掌握了这套从数据获取、清洗、分析到可视化的完整流程后,你就拥有了解读任何文本数据的基本能力。下次,你可以用它分析社交媒体上的热点话题,或是自己多年的日记,数据会告诉你那些被忽略的故事。

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

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

立即咨询