字典树实现_学习NLP的第3天——字典树

通过《自然语言处理入门》(何晗)的第2章来学习一下分词的常用算法,因此以下的实现方法都是通过HanLP实现的。这里主要记录我在学习过程中整理的知识、调试的代码和心得理解,以供其他学习的朋友参考。

字符串集合常用字典树(Trie树)存储,这是一种字符串上的树形数据结构。

字典树中每条边都对应一个字,从根节点往下的路径构成一个个字符串。字典树并不直接在节点上存储字符串,而是将词典视作根节点到某节点之间的一条路径,并在终点节点上做个“该节点对应词语的结尾”的标记。

字符串是一条路径,要查询一个单词,只需顺着这条路径从归根节点往下走。如果能走到特殊标记的节点,则说明该字符串在集合中,否则说明不存在。

6691eb2ed73b8a0ba88e79a126c830ce.png

图片来自《自然语言处理入门》(何晗)

例如,上图中的蓝色标记着该节点是一个词的结尾,数字是认为的编号。如“入门”、“自然人”等结束节点为蓝色的路径都可以成为词,而“自然语”等结束节点为白色的路径则不能成为词。

字典树的节点实现

每个节点都应该知道自己的子节点与对应的边,以及自己是否对应一个词。

我们用None来表示该节点不对应词语。

节点的Python实现如下:

class Node(object):    def __init__(self, value):        self._children = {}  # 子节点存储变量        self._value = value  # 当前节点的值    def _add_child(self, char, value, overwrite=False):        child = self._children.get(char)        if child is None:  # 判断当前节点是否已经存在字符char对应的child            child = Node(value)            self._children[char] = child        elif overwrite:  # 根据overwrite判断是否覆盖child的值            child._value = value        return child

字典树的增删改查实现

只要将以上节点连到根节点上,就得到了字典树。根节点继承自普通节点,并增加了一些面向用户的公开方法。因此,只要拿到根节点,就能抓住整棵字典树。

从确定有限状态自动机(DFA)的角度来讲,每个节点都是一个状态,状态表示当前已查询到的前缀。

有限状态自动机(DFA)

有限状态自动机(deterministic finite automaton, DFA)是一个能实现状态转移的自动机。对于一个给定的属于该自动机的状态和一个属于该自动机字母表Σ的字符,它都能根据事先给定的转移函数转移到下一个状态(这个状态可以是先前那个状态)。每次输入都会引起状态的改变或者不变。

字典树的Python实现如下:

class Trie(Node):    def __init__(self):        super().__init__(None)    def __contains__(self, key):        return self[key] is not None    def __getitem__(self, key):        state = self        for char in key:  # 遍历字符串中的每一个字符            state = state._children.get(char)  # 一直依据路径找到目标词            if state is None:                return None        return state._value    def __setitem__(self, key, value):        state = self        for i, char in enumerate(key):  # 枚举字符串中的每一个字符及其位置坐标            if i < len(key) - 1:  # 若当前词不是结尾词                state = state._add_child(char, None, False)            else:  # 若当前词是结尾词                state = state._add_child(char, value, True)

运行测试

我们参考书中方法对以上的字典树做如下测试:

if __name__ == '__main__':    trie = Trie()    # 增    trie['自然'] = 'nature'    trie['自然人'] = 'human'    trie['自然语言'] = 'language'    trie['自语'] = 'talkto oneself'    trie['入门'] = 'introduction'    print(trie['自然'])    # 删    trie['自然'] = None    print(trie['自然'])    # 改    print(trie['自然语言'])    trie['自然语言'] = 'human language'    print(trie['自然语言'])

运行结果

natureNonelanguagehuman language

字典树的使用是为了提高字典的查询速度,优化分词算法的效率。

本文使用教材:《自然语言处理入门》(何晗):2.4.1 - 2.4.3

本文中代码大部分引自该书中的代码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值