基于字典树可视化 COCA20000 词汇

COCA20000 是美国当代语料库中最常见的 20000 个词汇,不过实际上有一些重复,去重之后大概是 17600+ 个,这些单词是很有用,如果能掌握这些单词,相信会对英语的能力有一个较大的提升。我很早就下载了这些单词,并且自己编写了一个背单词的简易工具,如果有需要的同学,可以去看我的博客中搜索。今天这篇博客是利用字典树来堆单词的一个可视化。

字典树可视化词汇

下面就是一颗简单的 4 个单词的字典树,这个东西用来检索是很快的,这里我把最后的单词作为树的叶子节点。随着单词的不断增加,整个树也会不断的膨胀,不过这样就难以阅读了,所以我最终选择是把树的排列方向变成从又到右的形式。我之后要实现的字典树和下面这个没有什么本质的区别,只是更大一些而已,利用的数据就是 COCA 20000 的单词。

在这里插入图片描述

上面这个图形是使用 mermaid 绘制的,不过最终我采用的是 dot 语言(绘图指令就在下面),因为 mermaid 可能会遇到性能问题。实际上,dot 语言也是遇到了性能问题,因为单词实在是太多了,导致最后的图形太大了。我想了一些可能的优化措施,比如根据首字母来区分单词,这样的化加上大小写总共 52 个字母,可以把大的树分成 52 个小一点的树。不过,我也不是真的要去看这个树,所以就没有这样做。

在这里插入图片描述

代码处理

下面是全部的处理代码。

"""
字典树
目的是生成 COCA 单词的字典树,但是也可以用于其他单词或者词语(包括英语)。
"""
import jsonclass Node:"""字典树的一个节点,包含这个节点的值,以及它下面的节点,以及是否是一个单词的结尾。"""def __init__(self, val, is_end) -> None:self.val = valself.is_end = is_endself.children = {}def set_is_end(self) -> None:"""有些短的单词要重新设置,否则无法和长的区分开来,例如:are, area"""self.is_end = Trueclass DictTree:"""字典树"""def __init__(self):self.root = Node('/', False)self.stack = [] # 用来保存单词def append(self, word: str):"""向字典树中添加一个单词: 获取当前树的根节点:node = self.root遍历这个词的每一个字符 c,1. 如果该字符在当前树的子树中,则把当前树的子树指向当前树: node = node.children[c]如果当前字符 c 是最后一个字符,那么: node.is_end = True2. 如果该字符不在当前树的子树中,那么新建立一个节点,如果当前字符 c 是最后一个字符:is_end = True把它添加到当前树的子树中, node.children[c] = Node(c, is_end)"""node = self.rootfor i, c in enumerate(word):is_end = not i != len(word)-1if node.children.get(c):node = node.children[c]if is_end:node.set_is_end()else:node.children[c] = Node(c, is_end)node = node.children[c]def dumps(self) -> dict:"""序列化成字典对象"""return {"/": self.__dump(self.root)}def __dump(self, node: Node) -> dict:"""序列化成字典对象的内部方法,一个简单但是并不优雅的递归"""ret = {}self.stack.append(node.val)if not node.children:ret["word"] = "".join(self.stack[1:])for k, c in node.children.items():ret[k] = self.__dump(c)self.stack.pop()return ret# 生成dot描述
# 层序遍历 tips: 使用队列
def BFS_to_dot(tree) -> str:"""将树结构以层序遍历的方式转换为Dot语言表示的图形。Dot语言用于描述图形结构,本函数特别适用于将树结构可视化。:param tree: 输入的树结构,通常是一个字典或类似字典的对象,其中键值对表示节点及其子节点。:return: 返回一个表示树结构的Dot语言字符串。"""if not tree:returnqueue = [tree["/"]]          # 把树的根本身作为第一个节点加入队列count = 0                    # 子节点计数parent_count = 0             # 父节点计数parent_map = {0: "/"}        # 记录父节点序号和它的值nodes = ['n_0 [label="/"]']  # 点集edges = []                   # 边集while queue:node = queue.pop(0)if isinstance(node, dict):for val, child in node.items():queue.append(child)count += 1v = val if val != "word" else childparent_map[count] = vdot_node = f'n_{count} [label="{v}"]'dot_edge = f"n_{parent_count} -> n_{count};"nodes.append(dot_node)edges.append(dot_edge)parent_count += 1node_str = "\n".join(nodes)edge_str = "\n".join(edges)return f"digraph G {{\nrankdir=LR;\n{node_str};\n{edge_str}\n}}"if __name__ == "__main__":in_file = r"C:\Users\25735\Desktop\DragonEnglish\data\raw_txt\coca_no_order.txt"out_json_file = r"C:\Users\25735\Desktop\DragonEnglish\data\raw_txt\coca_dt_tree.json"out_dot_file = r"C:\Users\25735\Desktop\DragonEnglish\data\raw_txt\coca_dt_tree.dot"dt = DictTree()with open(in_file, "r", encoding="utf-8") as file:for word in [line.strip() for line in file.readlines()]:dt.append(word)dt_dumps = dt.dumps()# 序列化json写入with open(out_json_file, "w", encoding="utf-8") as file:json.dump(dt_dumps, file)# dot写入with open(out_dot_file, "w", encoding="utf-8") as file:file.write(BFS_to_dot(dt_dumps))print("EOF")

生成的文件
这里生成的 json 文件是压缩形式的,如果格式化的化,就超过 4m 了。
请添加图片描述

渲染图形

因为我安装了 graphviz 的插件,所以我直接在 VSCode 查看生成的 dot 文件时,它就在渲染了,不过渲染失败了。请添加图片描述

因为这个文件太大了,有十几万行(定义的节点就有几万个了)。

请添加图片描述

所以还是在本地来生成,我已经配置好了 graphviz 的环境了。一开始是生成的 png 格式,不过它提示分辨率有问题,因为节点太多了,导致生成的图形其实没法观看了。所以最终还是选择了 svg 和 pdf 格式,其中 pdf 格式生成的特别慢,至少是 20 分钟以上了。

请添加图片描述

生成的 svg 和 pdf

在这里插入图片描述

这两个文件的渲染都特别费劲,我的电脑打开有点吃力了。

请添加图片描述

请添加图片描述

对它的理解

如果是这 20000 个单词,它们的字母数是 150011 个,这是一个十分庞大的数字了。但是观察上面的字典树可以发现,其实有些单词是含有共同部分的,在计算的时候可以省去这部分,对于字典树来说就是计算其中的节点数就行了。因为我把完整的单词也算做节点了,所以要只计算单个字母的节点,这里我使用正则表达式来计算,最终的结果是: 54457 个。我觉得它对于我们记忆单词有一个很好的启示,那就是我们记忆单词并不是孤立的记忆每一个单词,每个单词之间是有联系的,随着记忆的单词越多,对于单词的掌握应该也是越来越熟悉的,但是太少了还是看不出来。而且这里只有前缀的联系,实际上还包括后缀的联系等。我会把这篇博客中产生的文件上传到 CSDN 中,如果有感兴趣的同学也可以自己下载体验。

请添加图片描述
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/21310.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Django的博客系统之用HayStack连接elasticsearch增加搜索功能(五)

上一篇:搭建基于Django的博客系统数据库迁移从Sqlite3到MySQL(四) 下一篇:基于Django的博客系统之增加类别导航栏(六) 功能概述 添加搜索框用于搜索博客。 需求详细描述 1. 添加搜索框用于搜索博客 描…

【数据密集型系统设计】软件系统的可靠性、可伸缩性、可维护性

文章目录 一. 数据密集型程序的特点以及遇到的问题二. 可靠性 : 即使出现问题,也能继续正确工作1 硬件故障2. 软件错误3. 人为错误 二. 可伸缩性1. 描述负载与推特的例子2. 描述性能-延迟和响应时间3. 应对负载的方法 四. 可维护性1. 可操作性:人生苦短&…

Chromebook Plus中添加了Gemini?

Chromebook Plus中添加了Gemini? 前言 就在5月29日,谷歌宣布了一项重大更新,将其Gemini人工智能技术集成到Chromebook Plus笔记本电脑中。这项技术此前已应用于谷歌的其他设备。华硕和惠普已经在市场上销售的Chromebook Plus机型,…

电脑缺少dll文件怎么解决,分享几种靠谱的解决方法

在现代科技高度发达的时代,电脑已经成为我们生活和工作中不可或缺的工具。然而,在使用电脑的过程中,我们可能会遇到一些问题,其中之一就是电脑丢失dll文件。那么,当我们面临这样的问题时,应该如何解决呢&am…

云原生架构案例分析_1.某旅行公司云原生改造

随着云计算的普及与云原生的广泛应用,越来越多的从业者、决策者清晰地认识到“云原生化将成为企业技术创新的关键要素,也是完成企业数字化转型的最短路径”。因此,具有前瞻思维的互联网企业从应用诞生之初就扎根于云端,谨慎稳重的…

SpringMVC:转发和重定向

1. 请求转发和重定向简介 参考该链接第9点 2. forward 返回下一个资源路径,请求转发固定格式:return "forward:资源路径"如 return "forward:/b" 此时为一次请求返回逻辑视图名称 返回逻辑视图不指定方式时都会默认使用请求转发in…

【Qt秘籍】[008]-Qt中的connect函数

在Qt框架中,connect函数是一个非常核心的函数,用于实现信号(Signals)和槽(Slots)之间的连接,它是Qt信号槽机制的关键所在。信号槽机制是一种高级的通信方式,允许对象在状态改变时通知…

牛客网刷题 | BC114 圣诞树 (不理解)

目前主要分为三个专栏,后续还会添加: 专栏如下: C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读! 初来乍到,如有错误请指出,感谢! 这道题没搞懂 也没找到视…

Nginx源码编译安装

Nginx NginxNginx的特点Nginx的使用场景Nginx 有哪些进程 使用源码编译安装Nginx准备工作安装依赖包编译安装Nginx检查、启动、重启、停止 nginx服务配置 Nginx 系统服务方法一:方法二: 访问Nginx页面 升级Nginx准备工作编译安装新版本Nginx验证 Nginx N…

SSMP整合案例第五步 在前端页面上拿到service层调数据库里的数据后列表

在前端页面上列表 我们首先看看前端页面 我们已经把数据传入前端控制台 再看看我们的代码是怎么写的 我们展示 数据来自图dataList 在这里 我们要把数据填进去 就能展示在前端页面上 用的是前端数据双向绑定 axios发送异步请求 函数 //钩子函数,VUE对象初始化…

设计模式(十四)行为型模式---访问者模式(visitor)

文章目录 访问者模式简介分派的分类什么是双分派?结构UML图具体实现UML图代码实现 优缺点 访问者模式简介 访问者模式(visitor pattern)是封装一些作用于某种数据结构中的元素的操作,它可以在不改变这个数据结构(实现…

全新市场阶段,Partisia BlockChain 将向 RWA、DeFi 等领域布局

Partisia Blockchain 是一个全新范式的 Layer1,该链通过 MPC 方案来构建链上隐私方案,同时该链通过系列独特且创新的设计,旨在进一步解决目前 Web3 中所面临的不可能三角问题,包括安全性、互操作性和可扩展性,为更多的…

NTFS磁盘格式读写工具:Tuxera NTFS 2021 for Mac

Tuxera NTFS 是一款用于 macOS 系统的 NTFS 文件系统驱动程序。NTFS 是 Windows 系统中常用的文件系统,而 macOS 默认只支持读取 NTFS 格式的磁盘,不能进行写入操作。因此,如果你需要在 macOS 上进行 NTFS 磁盘的写入操作,就需要安…

【一刷《剑指Offer》】面试题 28:字符串的排列

牛客对应题目链接:字符串的排列_牛客题霸_牛客网 (nowcoder.com) 力扣对应题目链接:LCR 157. 套餐内商品的排列顺序 - 力扣(LeetCode) 核心考点 :全排列问题, DFS。 一、《剑指Offer》对应内容 二、分析题…

JS(DOM、事件)

DOM 概念:Document Object Model,文档对象模型。将标记语言的各个组成部分封装为对应的对象: Document:整个文档对象Element:元素对象Attribute:属性对象Text:文本对象Comment:注释对象 JavaScript通过DOM,就能够对HTML进行操作: 改变 HTML 元素的内…

Windows端口本地转发

参考 微软Netsh interface portproxy 命令 界面端口代理的 Netsh 命令 | Microsoft Learn 使用Windows系统的portproxy功能配置端口转发 使用Windows系统的portproxy功能配置端口转发-阿里云帮助中心 (aliyun.com) 将来自0.0.0.0地址对端口35623的访问转发到172.18.106.16…

多维数组找最大值

调用JavaScript的一个内置函数&#xff1a;Math.max() <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title…

政安晨:【Keras机器学习示例演绎】(五十一)—— 利用广义网络、深度网络和交叉网络进行结构化数据学习

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 本文目标&#xff1a;使用 "宽深 "和 …

redis如何实现分布式锁

Redisson是怎么实现分布式锁的 分布式锁&#xff1a;Redisson 提供了一种简单而强大的方式来实现分布式锁。 它支持多种锁模式&#xff0c;如公平锁、可重入锁、读写锁等&#xff0c;并且提供了锁的超时设置和自动释放功能。 锁的获取 在Redisson中常见获取锁的方式有 lock() …

【代码随想录训练营】【Day 37】【贪心-4】| Leetcode 840, 406, 452

【代码随想录训练营】【Day 37】【贪心-4】| Leetcode 840, 406, 452 需强化知识点 python list sort的高阶用法&#xff0c;两个key&#xff0c;另一种逆序写法python list insert的用法 题目 860. 柠檬水找零 思路&#xff1a;注意 20 块找零&#xff0c;可以找3张5块升…