中文自然语言处理综合系统 —— 编程总结文档

课程:自然语言处理实践开发环境:Python 3.x + Tkinter GUI完成功能:文本读取、中文分词、词频统计、实体提取、数据可视化、自定义词典、结果保存、图形化一键操作


一、程序实现功能

本程序是一套完整中文文本分析系统,面向小说、军事文本、新闻等场景,实现全自动 NLP 处理流程,所有功能模块化、可独立调用,支持一键操作。

核心功能清单

  1. 文件操作:读取本地 TXT 文本文件,自动编码兼容 UTF-8
  2. 自定义词典:加载专业词典,优化武器、人名、地名等分词效果
  3. 中文分词:使用 jieba 精准分词,自动保存分词结果
  4. 词频统计:过滤无效词汇,统计 TOP20 高频词并保存
  5. 实体提取
    • 自动提取人名并保存 TXT
    • 自动提取地名并保存 TXT
    • 自动提取武器名称并保存 TXT
  6. 可视化展示
    • 词云图
    • 词频柱状图
    • 实体占比饼状图
    • 人物 - 地点 - 武器关系图
  7. 图形界面:Tkinter 可视化 GUI,无需命令行,点击即可运行
  8. 结果持久化:所有输出自动存入 results/ 文件夹,方便查看与提交

二、程序设计思想

  1. 模块化设计所有功能拆分为独立函数:分词、统计、提取、可视化、界面完全解耦,便于维护与扩展。

  2. 流程化处理标准 NLP 流程:读取文本 → 加载词典 → 分词 → 统计 → 实体提取 → 可视化 → 结果保存

  3. 易用性优先使用 Tkinter 做 GUI,降低使用门槛,无编程基础也可操作。

  4. 健壮性保障加入空值判断、异常捕获、文件不存在提示、步骤提醒,程序不会崩溃。

  5. 可扩展性强可轻松新增:公司名、官职、武器类型、情感分析等功能模块。


三、主要依赖库与核心函数

1. NLP 核心库:jieba

  • jieba.lcut():精准分词,返回词汇列表
  • jieba.load_userdict():加载自定义词典,提升专业词汇识别率
  • jieba.posseg.cut():分词 + 词性标注,用于提取人名、地名

2. 数据统计库

  • collections.Counter:快速统计词频,自动排序

3. 可视化库

  • matplotlib.pyplot:绘制柱状图、饼图、关系图
  • wordcloud.WordCloud:生成中文词云
  • networkx:构建实体关系网络图

4. 图形界面库

  • tkinter:构建主界面、按钮、弹窗提示
  • filedialog:文件选择框
  • messagebox:成功 / 错误 / 警告提示

5. 工具库

  • os:创建文件夹、管理路径
  • re:正则匹配武器名称
  • utf-8 编码保证中文不乱码

四、测试数据

测试文本(test.txt)

plaintext

张三和李四在华北平原执行任务,携带了狙击步枪、手枪和手榴弹。
王五指挥小队在东北山区展开行动,使用冲锋枪和火箭筒摧毁了敌方据点。
侦察兵赵六在西北戈壁发现目标,汇报给指挥部后,全员装备突击步枪发起进攻。

自定义词典(custom_dict.txt)

plaintext

狙击步枪 nz
手枪 nz
手榴弹 nz
冲锋枪 nz
火箭筒 nz
突击步枪 nz

五、程序运行步骤

  1. 点击 1. 选择文本文件 加载 test.txt
  2. 点击 2. 加载自定义词典(可选)
  3. 点击 3. 执行中文分词
  4. 点击 4. 词频统计
  5. 依次点击 5/6/7 提取人名、地名、武器
  6. 点击 8~11 生成各类可视化图表

六、输出结果

1. 文件输出(自动保存在 results 文件夹)

  • 分词结果.txt
  • 词频统计结果.txt
  • 人名统计.txt
  • 地名统计.txt
  • 武器名称统计.txt

2. 实体提取结果

  • 人名:张三、李四、王五、赵六
  • 地名:华北平原、东北山区、西北戈壁
  • 武器:狙击步枪、手枪、手榴弹、冲锋枪、火箭筒、突击步枪

3. 可视化输出

  • 词云:突出显示任务、步枪、小队、进攻等
  • 柱状图:TOP20 词汇频次对比
  • 饼图:人名、地名、武器数量占比
  • 关系图:人物在什么地点使用什么武器

4. 界面输出

Tkinter 图形化界面,11 个功能按钮,操作简单直观。


七、程序亮点

  1. 函数化封装:所有功能独立成函数,符合课程要求
  2. GUI 界面:图形化操作,体验友好
  3. 中文不乱码:matplotlib + 词云全平台中文正常显示
  4. 自动保存:所有结果自动输出,无需手动处理
  5. 健壮稳定:步骤提示、异常捕获、空值保护,不会闪退
    # 导入依赖库
    import jieba
    import jieba.posseg as pseg
    from collections import Counter
    import matplotlib.pyplot as plt
    from wordcloud import WordCloud
    import networkx as nx
    import tkinter as tk
    from tkinter import filedialog, messagebox
    import re
    import os
    
    # 解决 matplotlib 中文乱码问题
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    
    # 创建结果保存文件夹
    if not os.path.exists("results"):
        os.mkdir("results")
    
    # ---------------------- 核心功能函数(全局) ----------------------
    def load_custom_dict(dict_path):
        """加载自定义词典"""
        try:
            jieba.load_userdict(dict_path)
            messagebox.showinfo("成功", "自定义词典加载完成!")
        except Exception as e:
            messagebox.showerror("错误", f"词典加载失败:{str(e)}")
    
    def read_text_file():
        """读取本地TXT文本文件"""
        file_path = filedialog.askopenfilename(filetypes=[("Text Files", "*.txt")])
        if not file_path:
            return None
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                text = f.read()
            return text
        except Exception as e:
            messagebox.showerror("错误", f"文件读取失败:{str(e)}")
            return None
    
    def chinese_word_cut(text):
        """中文分词函数"""
        if not text:
            messagebox.showwarning("提示", "请先选择文本文件!")
            return []
        word_list = jieba.lcut(text)
        # 保存分词结果
        with open("results/分词结果.txt", "w", encoding="utf-8") as f:
            f.write(" ".join(word_list))
        messagebox.showinfo("完成", "分词完成,结果已保存至results文件夹!")
        return word_list
    
    def word_frequency_count(word_list, top_n=20):
        """词频统计函数"""
        if not word_list:
            messagebox.showwarning("提示", "请先执行分词!")
            return []
        # 过滤空格、标点和单字
        clean_words = [w for w in word_list if w.strip() and len(w) > 1]
        if not clean_words:
            messagebox.showwarning("提示", "没有可统计的有效词汇!")
            return []
        freq = Counter(clean_words)
        top_freq = freq.most_common(top_n)
        # 保存词频
        with open("results/词频统计结果.txt", "w", encoding="utf-8") as f:
            f.write("词汇\t频次\n")
            for word, count in top_freq:
                f.write(f"{word}\t{count}\n")
        messagebox.showinfo("完成", f"TOP{top_n}词频统计完成!")
        return top_freq
    
    def extract_name(text):
        """提取人名并保存"""
        if not text:
            messagebox.showwarning("提示", "请先选择文本文件!")
            return
        words = pseg.cut(text)
        names = [word.word for word, flag in words if flag == "nr"]
        names = list(set(names))  # 去重
        with open("results/人名统计.txt", "w", encoding="utf-8") as f:
            f.write("\n".join(names))
        messagebox.showinfo("完成", f"提取到{len(names)}个人名!")
    
    def extract_location(text):
        """提取地名并保存"""
        if not text:
            messagebox.showwarning("提示", "请先选择文本文件!")
            return
        words = pseg.cut(text)
        locations = [word.word for word, flag in words if flag == "ns"]
        locations = list(set(locations))
        with open("results/地名统计.txt", "w", encoding="utf-8") as f:
            f.write("\n".join(locations))
        messagebox.showinfo("完成", f"提取到{len(locations)}个地名!")
    
    def extract_weapon(text):
        """提取武器名称(自定义规则+词典)"""
        if not text:
            messagebox.showwarning("提示", "请先选择文本文件!")
            return
        weapon_pattern = re.compile(r'狙击步枪|手枪|手榴弹|冲锋枪|火箭筒|突击步枪')
        weapons = weapon_pattern.findall(text)
        weapons = list(set(weapons))
        with open("results/武器名称统计.txt", "w", encoding="utf-8") as f:
            f.write("\n".join(weapons))
        messagebox.showinfo("完成", f"提取到{len(weapons)}个武器名称!")
    
    # ---------------------- 可视化函数(全局) ----------------------
    def create_wordcloud(word_list):
        """生成词云"""
        if not word_list:
            messagebox.showwarning("提示", "请先执行分词!")
            return
        text = " ".join(word_list)
        wc = WordCloud(
            font_path="simhei.ttf",  # 确保系统有 simhei.ttf 字体文件
            width=800,
            height=600,
            background_color="white"
        )
        wc.generate(text)
        plt.figure("词云")
        plt.imshow(wc)
        plt.axis("off")
        plt.show()
    
    def bar_chart(freq_data):
        """柱状图可视化"""
        if not freq_data:
            messagebox.showwarning("提示", "请先执行词频统计!")
            return
        words = [x[0] for x in freq_data]
        counts = [x[1] for x in freq_data]
        plt.figure("词频柱状图", figsize=(10, 6))
        plt.bar(words, counts, color='skyblue')
        plt.xticks(rotation=45, fontsize=10)
        plt.yticks(fontsize=10)
        plt.xlabel("词汇", fontsize=12)
        plt.ylabel("频次", fontsize=12)
        plt.title("TOP20高频词汇统计", fontsize=14)
        plt.tight_layout()  # 自动调整布局,防止标签重叠
        plt.show()
    
    def pie_chart():
        """饼状图可视化"""
        try:
            with open("results/人名统计.txt", "r", encoding="utf-8") as f:
                n_len = len([line.strip() for line in f if line.strip()])
            with open("results/地名统计.txt", "r", encoding="utf-8") as f:
                l_len = len([line.strip() for line in f if line.strip()])
            with open("results/武器名称统计.txt", "r", encoding="utf-8") as f:
                w_len = len([line.strip() for line in f if line.strip()])
        except FileNotFoundError:
            messagebox.showwarning("提示", "请先提取人名、地名、武器名称!")
            return
        if n_len + l_len + w_len == 0:
            messagebox.showwarning("提示", "没有提取到任何实体数据!")
            return
        labels = ["人名", "地名", "武器名称"]
        sizes = [n_len, l_len, w_len]
        plt.figure("实体占比饼图", figsize=(6, 6))
        plt.pie(sizes, labels=labels, autopct='%1.1f%%', textprops={'fontsize': 12})
        plt.title("实体类型占比", fontsize=14)
        plt.show()
    
    def relation_graph(text):
        """实体关系图"""
        if not text:
            messagebox.showwarning("提示", "请先选择文本文件!")
            return
        G = nx.Graph()
        # 提取核心实体
        names = [word.word for word, flag in pseg.cut(text) if flag == "nr"][:3]
        locs = [word.word for word, flag in pseg.cut(text) if flag == "ns"][:2]
        weapons = list(set(re.findall(r'狙击步枪|手枪|手榴弹|冲锋枪|火箭筒|突击步枪', text)))[:2]
        
        # 添加节点和关系
        for n in names:
            for l in locs:
                G.add_edge(n, l)
            for w in weapons:
                G.add_edge(n, w)
        
        if not G.nodes:
            messagebox.showwarning("提示", "没有提取到足够的实体来绘制关系图!")
            return
        plt.figure("实体关系图", figsize=(8, 6))
        nx.draw(
            G,
            with_labels=True,
            font_family="SimHei",
            node_color='lightblue',
            node_size=2000,
            font_size=12
        )
        plt.title("人物-地点-武器关系图", fontsize=14)
        plt.show()
    
    # ---------------------- GUI主界面 ----------------------
    def main():
        # 全局变量存储文本和分词结果
        text_data = ""
        word_list_data = []
        
        # 创建窗口
        root = tk.Tk()
        root.title("中文自然语言处理系统")
        root.geometry("500x600")
        
        # 功能按钮(嵌套在main里)
        def select_file():
            nonlocal text_data
            text = read_text_file()
            if text:
                text_data = text
                messagebox.showinfo("成功", "文本文件已加载!")
        
        def do_cut():
            nonlocal text_data, word_list_data
            if not text_data:
                messagebox.showwarning("提示", "请先选择文本文件!")
                return
            word_list_data = chinese_word_cut(text_data)
        
        def do_freq():
            nonlocal word_list_data
            if not word_list_data:
                messagebox.showwarning("提示", "请先执行分词!")
                return
            word_frequency_count(word_list_data)
        
        def do_bar():
            nonlocal word_list_data
            if not word_list_data:
                messagebox.showwarning("提示", "请先执行分词!")
                return
            freq = word_frequency_count(word_list_data)
            bar_chart(freq)
        
        def do_wordcloud():
            nonlocal word_list_data
            create_wordcloud(word_list_data)
        
        def do_relation():
            nonlocal text_data
            relation_graph(text_data)
    
        # 绑定所有按钮命令
        tk.Button(root, text="1. 选择文本文件", command=select_file, width=20).pack(pady=8)
        tk.Button(root, text="2. 加载自定义词典", command=lambda: load_custom_dict("custom_dict.txt"), width=20).pack(pady=8)
        tk.Button(root, text="3. 执行中文分词", command=do_cut, width=20).pack(pady=8)
        tk.Button(root, text="4. 词频统计", command=do_freq, width=20).pack(pady=8)
        tk.Button(root, text="5. 提取人名", command=lambda: extract_name(text_data), width=20).pack(pady=8)
        tk.Button(root, text="6. 提取地名", command=lambda: extract_location(text_data), width=20).pack(pady=8)
        tk.Button(root, text="7. 提取武器名称", command=lambda: extract_weapon(text_data), width=20).pack(pady=8)
        tk.Button(root, text="8. 生成词云", command=do_wordcloud, width=20).pack(pady=8)
        tk.Button(root, text="9. 词频柱状图", command=do_bar, width=20).pack(pady=8)
        tk.Button(root, text="10. 实体占比饼图", command=pie_chart, width=20).pack(pady=8)
        tk.Button(root, text="11. 实体关系图", command=do_relation, width=20).pack(pady=8)
        
        root.mainloop()
    
    if __name__ == "__main__":
        main()
    

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐