PyHanLP&kenlm&HarvestText领域自适应文本挖掘工具

新词发现

新词发现是 NLP 的基础任务之一,通过对已有语料进行挖掘,从中识别出新词。它主要是希望通过无监督发掘一些语言特征(主要是统计特征),来判断一批语料中哪些字符片段可能是一个新词。“新词发现”是一个比较通俗的叫法,更准确的叫法应该是“无监督构建词库”,因为原则上它能完整地构建一个词库出来,而不仅仅是“新词”。当然,你可以将它跟常用词库进行对比,删掉常见词,就可以得到新词了。

特定领域的专有名词也可归属于新词的范畴。何出此言呢?通常我们会很容易找到通用领域的词表,但要找到某个具体领域的专有名词则非常困难,因此特定领域的专有名词相对于通用领域的词语即为新词。换言之,“新”并非只是时间上的概念,同样可以迁移到领域或空间上。因此,新词发现不仅可以挖掘随时间变化而产生的新词,也可以挖掘不同领域的专有名词

新词发现的方法

目前主要有基于规则和基于统计两种方法:

  • 基于规则的方法:根据新词的构词特征或外型特征建立规则库、专业词库或模式库,然后通过规则匹配发现新词。
  • 基于统计的方法
    • 有监督:有监督方法利用标注语料,将新词发现看作分类或者序列标注问题。
    • 无监督:不依赖于任何已有的词库、分词工具和标注语料,仅仅根据词的共同特征,利用统计策略将一段大规模语料中可能成词的文本片段全部提取出来,然后再利用语言知识排除不是新词语的“无用片段”或者计算相关度,寻找相关度最大的字与字的组合。最后,把所有抽取得到的词和已有的词库进行比较,就能得到新词

项目开源地址

https://github.com/bojone/word-discovery

PyHanLP 新词识别)

HarvestText: 领域自适应文本挖掘工具(新词发现、情感分析、实体链接等)√

语言模型简介

语言模型是计算条件概率

的模型,其中$w_1,w_2,…,w_{n−1}$是句子中的前$n−1$个词(或字),$w_n$是第$n$个词(或字)。语言模型在很多方面都有应用,比如说分词、语音识别、机器翻译等。为了得到语言模型,有很多方法,比如说最简单的是“统计+平滑”的方法,还有最大熵语言模型、CRF语言模型等,而当前深度学习框架下研究得很多的是“神经网络语言模型”,它的大概思路是:==$p(w_n|w_1,w_2,…,w_{n−1})$是关于$w1,w2,…,wn$的一个函数,这个函数的具体形式我不知道,所以利用神经网络去拟合它,为了更好地拟合,并且减少模型参数,还把词语“嵌入”到实数空间中,用短向量来表示词语,跟语言模型一起训练。从这个角度看,词向量只是语言模型的副产品。==

语言模型生成的词向量能够较好地表示语义,这是很有趣的,却也是在情理之中。什么是语义?对人类来说,语义是一种推理和理解的过程,而我们的语言模型,就是从前$n−1$个字推测下一个字,这也是一个推理的过程。既然包含了推理成分在里边,就有可能捕捉到语义了。

详细的算法

完整的算法步骤如下:

1
2
3
4
5
第一步,统计:选取某个固定的nn,统计2grams、3grams、…、ngrams,计算它们的内部凝固度,只保留高于某个阈值的片段,构成一个集合GG;这一步,可以为2grams、3grams、…、ngrams设置不同的阈值,不一定要相同,因为字数越大,一般来说统计就越不充分,越有可能偏高,所以字数越大,阈值要越高;

第二步,切分:用上述grams对语料进行切分(粗糙的分词),并统计频率。切分的规则是,只有一个片段出现在前一步得到的集合GG中,这个片段就不切分,比如“各项目”,只要“各项”和“项目”都在GG中,这时候就算“各项目”不在GG中,那么“各项目”还是不切分,保留下来;

第三步,回溯:经过第二步,“各项目”会被切出来(因为第二步保证宁放过,不切错)。回溯就是检查,如果它是一个小于等于nn字的词,那么检测它在不在GG中,不在就出局;如果它是一个大于nn字的词,那个检测它每个nn字片段是不是在GG中,只要有一个片段不在,就出局。还是以“各项目”为例,回溯就是看看,“各项目”在不在3gram中,不在的话,就得出局。

每一步的补充说明:

1
2
3
4
5
1、较高的凝固度,但综合考虑多字,是为了更准,比如两字的“共和”不会出现在高凝固度集合中,所以会切开(比如“我一共和三个人去玩”,“共和”就切开了),但三字“共和国”出现在高凝固度集合中,所以“中华人民共和国”的“共和”不会切开;

2、第二步就是根据第一步筛选出来的集合,对句子进行切分(你可以理解为粗糙的分词),然后把“粗糙的分词结果”做统计,注意现在是统计分词结果,跟第一步的凝固度集合筛选没有交集,我们认为虽然这样的分词比较粗糙,但高频的部分还是靠谱的,所以筛选出高频部分;

3、第三步,例如因为“各项”和“项目”都出现高凝固度的片段中,所以第二步我们也不会把“各项目”切开,但我们不希望“各项目”成词,因为“各”跟“项目”的凝固度不高(“各”跟“项”的凝固度高,不代表“各”跟“项目”的凝固度高),所以通过回溯,把“各项目”移除(只需要看一下“各项目”在不在原来统计的高凝固度集合中即可,所以这步计算量是很小的)

细节

  1. Linux环境CentOS系统 kenlm 的自行编译

    kenlm 是一个C++编写的语言模型工具,具有速度快、占用内存小的特点,也提供了Python接口。使用了语言模型工具kenlmcount_ngrams 程序来统计ngram。

    首先,安装必要的包:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    sudo yum install boost
    sudo yum install boost-devel
    sudo yum install libboost-program-options-dev
    sudo yum install zlib
    sudo yum install zlib-devel
    sudo yum install libbz2-dev
    sudo yum install lzma-devel
    sudo yum install eigen3
    sudo yum install xz-devel
    sudo yum install bzip2-devel

    然后下载&解压 kenlm.tar.gz工具包

    1
    wget -O - https://kheafield.com/code/kenlm.tar.gz |tar xz

    进入子目录进行编译(有用的脚本在build/bin之中)

    1
    2
    3
    4
    mkdir -p kenlm/build
    cd kenlm/build
    cmake ..
    make -j 4

    python库的安装方式:

    1
    pip install https://github.com/kpu/kenlm/archive/master.zip

    ==把生成的 build/bin/count_ngrams 放到跟 word_discovery.py 同一目录下==

    测试是否可运行:

    1
    ./count_ngrams -o 4 --memory=50% --write_vocab_list thucnews.chars <thucnews.corpus >thucnews.ngrams
  • kenlm 的简单使用

    训练一个==4-gram==的语言模型(训练的文本分好词(用空格隔开,如果你是做基于字的模型,就把模型的每个字用空格隔开)):

    1
    2
    3
    python p.py|./kenlm/bin/lmplz -o 4 > weixin.arpa
    # 压缩模型为二进制,方便模型快速加载:
    ./kenlm/bin/build_binary weixin.arpa weixin.klm

    简单使用:

    1
    2
    3
    4
    5
    6
    7
    8
    import kenlm

    model = kenlm.Model('weixin.klm')
    model.score('微 信', bos=False, eos=False)
    '''
    score函数输出的是对数概率,即log10(p('微 信')),其中字符串可以是gbk,也可以是utf-8
    bos=False, eos=False意思是不自动添加句首和句末标记符
    '''
  1. 在第二次遍历词库以得到候选词的时候,使用了Trie 树结构来加速搜索字符串是否出现过某个ngram。Trie树或者其变种基本上是所有基于词典的分词工具的标配,就是因为它可以加快搜索字符串中是否出现过词典中的词。

代码讲解

  • 逐句地把原始语料给yield出来
1
def text_generator():
  • 参数配置
1
2
min_count = 32
order = 4

顺便提一下,因为是无监督训练,语料一般都是越大越好,几百M到几个G都可以,==但其实如果你只要几M的语料(比如一部小说),也可以直接测试,也能看到基本的效果(但可能要修改下面的参数)==

  • 用结巴分词加载这个得到的词库(不用它自带的词库,并且关闭新词发现功能),这就构成了一个基于无监督词库的分词工具

参考

新词发现

Linux环境 kenlm 的自行编译

重新写了之前的新词发现算法:更快更好的新词发现

《【中文分词系列】 5. 基于语言模型的无监督分词》

《【中文分词系列】 8. 更好的新词发现算法》

使用kenlm工具训练统计语言模型


新词发现
http://example.com/2020/01/20/2020-01-20-新词发现/
作者
NSX
发布于
2020年1月20日
许可协议