自然语言处理hanlp------7-1双数组字典树

简介: 自然语言处理hanlp------7-1双数组字典树

前言

上一节的BinTrie的接口做到了1000万字每秒的速度,比Python的64万字每秒提高了两个数量级。但我们是算法工程师,要做到挑战极限。


提示:以下是本篇文章正文内容,下面案例可供参考


一、双数组字典树(DAT)是什么?

Trie树本质是一个确定的有限状态自动机(DFA),核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。


但由于Trie树的稀疏现象严重,空间利用率较低为了让Trie树实现占用较少的空间,同时还要保证查询的效率,最后提出了用2个线性数组来进行Trie树的表示,即双数组Trie(Double Array Trie).

双数组Trie(Double-ArrayTrie)是trie树的一个简单而有效的实现,由两个整数数组构成,一个是base[],另一个是check[]。


base数组的每个元素表示一个Trie节点,即一个状态(分为空闲状态和占用状态)

check数组的每个元素表示某个状态的前驱状态


公式如下:

p = base[b] + c
check[p] = base[b]


若不满足此条件,则状态转移失败。举个例子,当前状态为自然(状态由一个整数下标表示,下同),我们想知道是否可以转移到自然人。那么我们先执行自然人=base [自然]+人,然后检查 check [ 自然人]==base[自然]是否成立,据此判断转移是否成功。

也就是说,我们仅仅执行一次加法和一次整数比较就能进行状态转移,因而只花费了常数时间。


二、了解一下源码

1.定义一个双数组

代码如下(示例):

class DoubleArrayTrie(object):
    def __init__(self, dic: dict) -> None:
        m = JClass('java.util.TreeMap')()
        for k, v in dic.items():
            m[k] = v
        DoubleArrayTrie = JClass('com.hankcs.hanlp.collection.trie.DoubleArrayTrie')
        dat = DoubleArrayTrie(m)
        self.base = dat.getBase()
        self.check = dat.getCheck()
        self.value = dat.getValueArray([''])

这里的双数组的构造直接由Hanlp实现,直接拿到对应的base,check,value值


2.状态转移

前面有讲述,Python的散列值不适合字符,所以直接借用 javahashcode()

代码如下(示例):

@staticmethod
    def char_hash(c) -> int:
        return JClass('java.lang.Character')(c).hashCode()

此处根据java的character对象创建字符并用hashcode方法取得其散列值


考虑到不是所有节点都对应词语终点,只有字典树中的终点节点(蓝色节点)才对应一个词语。为了区分它们,实现上可以借鉴C语言中的设计,在每个字符串末尾添加一个散列值等于0的\0,也就是说,\0充当了蓝色节点的角色,这样普通节点就不需要分配内存标记自己的颜色了。考虑到用户输入的文本中也可能含有\0,为了避免与此混淆,HanLP采用将文本字符的hashCode加一。一个兼容\0的转移函数的实现如下:

def transition(self, c, b) -> int:
        """
        状态转移
        :param c: 字符
        :param b: 初始状态
        :return: 转移后的状态,-1表示失败
        """
        p = self.base[b] + self.char_hash(c) + 1
        if self.base[b] == self.check[p]:
            return p
        else:
            return -1

除了额外加一的技巧外,这段代码与双数组字典树一致。


3.查询

有了状态转移函数,我们再对键取值查询就方便多了,带上多出来的+1(\0),也就是状态转移至多是len(key)+1次。

def __getitem__(self, key: str):
        b = 0
        for i in range(0, len(key)):  # len(key)次状态转移
            p = self.transition(key[i], b)
            if p is not -1:
                b = p
            else:
                return None
        p = self.base[b]  # 按字符'\0'进行状态转移
        n = self.base[p]  # 查询base
        if p == self.check[p] and n < 0:  # 状态转移成功且对应词语结尾
            index = -n - 1  # 取得字典序
            return self.value[index]
        return None


测试一下效果:

if __name__ == '__main__':
    dic = {'自然': 'nature', '自然人': 'human', '自然语言': 'language', '自语': 'talk  to oneself', '入门': 'introduction'}
    dat = DoubleArrayTrie(dic)
    #assert dat['自然'] == 'nature'
    #assert dat['自然语言'] == 'language'
    #assert dat['不存在'] is None
    #assert dat['自然\0在'] is None
    print(dat['自然'])
    print(dat['自然语言'])
    print(dat['不存在'])
    print(dat['自然\0在'])

20210125124936895.png


总结

多看,多思考,不懂的先保留,重在理解晗佬的思路,解决方案。

相关文章
|
存储 自然语言处理
自然语言处理hanlp------9基于双数组字典树的AC自动机
自然语言处理hanlp------9基于双数组字典树的AC自动机
自然语言处理hanlp------9基于双数组字典树的AC自动机
|
存储 自然语言处理 算法
自然语言处理hanlp------7-2双数组字典树(*初学者可选择性学习)
自然语言处理hanlp------7-2双数组字典树(*初学者可选择性学习)
自然语言处理hanlp------7-2双数组字典树(*初学者可选择性学习)
|
自然语言处理 算法 Java
自然语言处理hanlp------6-2字典树的实现
自然语言处理hanlp------6-2字典树的实现
自然语言处理hanlp------6-2字典树的实现
|
自然语言处理 算法 Java
自然语言处理hanlp------6-1字典树的实现
自然语言处理hanlp------6-1字典树的实现
自然语言处理hanlp------6-1字典树的实现
|
2月前
|
机器学习/深度学习 自然语言处理 监控
利用深度学习技术实现自然语言处理中的情感分析
本文将深入探讨如何利用深度学习技术在自然语言处理领域中实现情感分析。通过介绍情感分析的背景和原理,结合深度学习模型如LSTM、BERT等的应用,帮助读者了解情感分析的重要性以及如何利用最新技术实现更准确的情感识别。
|
2月前
|
机器学习/深度学习 自然语言处理 算法
探索机器学习中的自然语言处理技术
【2月更文挑战第16天】 在数字化和智能化的浪潮中,自然语言处理(NLP)技术已成为连接人类与机器沟通的重要桥梁。本文深入探讨了机器学习在自然语言处理中的应用,包括最新的模型架构、算法优化技巧及实际场景中的挑战和解决方案。通过逻辑严密的分析,我们将揭示如何有效利用机器学习提升NLP系统的性能,同时对未来发展趋势进行预测。
23 0
|
2月前
|
机器学习/深度学习 自然语言处理 监控
利用深度学习技术实现自然语言处理中的情感分析
本文将深入探讨如何利用深度学习技术,特别是神经网络模型,来实现自然语言处理领域中的情感分析任务。通过结合深度学习算法和大规模文本数据集,可以实现更准确和高效的情感分析,为情感识别和情感推断提供更好的解决方案。
|
2月前
|
机器学习/深度学习 自然语言处理
自然语言处理技术(NLP)
自然语言处理技术(NLP)
41 1
|
3月前
|
自然语言处理
举例说明自然语言处理(NLP)技术
举例说明自然语言处理(NLP)技术
18 0
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
springboot基于人工智能和自然语言理解技术的医院智能导医系统源码
智能导诊系统可为患者提供线上挂号智能辅助服务,患者根据提示手动输入自己的基本症状,通过智能对话方式,该系统会依据大数据一步步帮助患者“诊断”,并最终推荐就医的科室和相关专家。患者可自主选择,实现“一键挂号”。这一模式将精确的导诊服务前置,从源头上让医疗服务更高效。
373 2