您的位置:首页 > 其它

转 --自然语言工具包(NLTK)小结

2017-04-18 22:45 477 查看
原作者:http://www.cnblogs.com/I-Tegulia/category/706685.html

1.自然语言工具包(NLTK)
NLTK 创建于2001 年,最初是宾州大学计算机与信息科学系计算语言学课程的一部分。从那以后,在数十名贡献者的帮助下不断发展壮大。如今,它已被几十所大学的课程所采纳,并作为许多研究项目的基础。表P -2 列出了NLTK 的一些最重要的模块。

这本书提供自然语言处理领域非常方便的入门指南。它可以用来自学,也可以作为自然语言处理或计算语言学课程的教科书,或是人工智能、文本挖掘、语料库语言学课程的补充读物。本书的实践性很强,包括几百个实际可用的例子和分级练习。

本书基于Python 编程语言及其上的一个名为自然语言工具包(Natural Language Toolkit ,简称NLTK)的开源库。NLTK 包含大量的软件、数据和文档,所有这些都可以从http://www.nltk.org/免费下载。NLTK 的发行版本支持Windows、Macintosh 和Unix 平台。

2. 获得文本语料和词汇语料
2.1 获取文本语料库
通过nltk.download()下载配套的数据,本文文本语料库包括以下:

古腾堡语料库(Gutenberg)

NLTK 包含古腾堡项目(Project Gutenberg)电子文本档案的经过挑选的一小部分文本。该项目大约有25,000(现在是36,000 了)本免费电子图书。

网络和聊天文本

NLTK 的网络文本小集合的内容包括Firefox 交流论坛,在纽约无意听到的对话,《加勒比海盗》的电影剧本,个人广告和葡萄酒的评论等

布朗语料库

布朗语料库是第一个百万词级的英语电子语料库的,由布朗大学于1961 年创建。这个语料库包含500 个不同来源的文本,按照文体分类,如:新闻、社论等。

路透社语料库

路透社语料库包含10,788 个新闻文档,共计130 万字。这些文档分成90 个主题,按照“训练”和“测试”分为两组。这样分割是为了训练和测试算法的,这种算法自动检测文档的主题。

就职演说语料库

就职演说语料库,实际上是55 个文本的集合,每个文本都是一个总统的演说。这个集合的一个有趣特性是它的时间维度

标注文本语料库

包含语言学标注,有词性标注、命名实体、句法结构、语义角色等。NLTK 中提供了很方便的方式来访问这些语料库中的几个,还有一个包含语料库和语料样本的数据包。

其他语言的语料库
NLTK 包含多国语言语料库。

文本语料库的结构:语料库结构最简单的一种没有任何结构,仅仅是一个文本集合。通常,文本会按照其可能对应的文体、来源、作者、语言等分类。有时,这些类别会重叠,尤其是在按主题分类的情况下,因为一个文本可能与多个主题相关。偶尔的,文本集有一个时间结构,新闻集合是最常见的例子。NLTK 语料库阅读器支持高效的访问大量语料库,并且能用于处理新的语料库。

表2-3 NLTK中定义的基本语料库函数

载入你自己的语料库:如果你有自己收集的文本文件,并且想使用前面讨论的方法访问它们,你可以很容易地
在NLTK 中的PlaintextCorpusReader 帮助下载入它们。

2.2 条件频率分布
条件频率分布是频率分布的集合,每个频率分布有一个不同的“条件”,这个条件通常是文本的类别。当语料文本被分为几类(文体、主题、作者等)时,我们可以计算每个类别独立的频率分布。这将允许我们研究类别之间的系统性差异。

条件频率分布是一个对许多NLP 任务都有用的数据结构。
表2-4 NLTK中条件概率分布: 定义、访问和可视化一个计数的条件概率分布的常用方法和习惯用法

2.3 词典资源
词典或者词典资源是一个词和/或短语以及一些相关信息的集合,例如:词性和词意定义等相关信息。词典资源附属于文本,通常在文本的帮助下创建和丰富。复杂的词典资源包括在词汇项内和跨词汇项的复杂的结构。

NLTK包括的词典资源:

词汇列表语料库
NLTK 包括一些仅仅包含词汇列表的语料库。词汇语料库是Unix 中的/usr/dict/words 文件,被一些拼写检查程序使用。我们可以用它来寻找文本语料中不寻常的或拼写错误的词汇。

还有一个停用词语料库,就是那些高频词汇,如:the,to,我们有时在进一步的处理之前想要将它们从文档中过滤。停用词通常几乎没有什么词汇内容,而它们的出现会使区分文本变困难。

发音的词典

一个稍微丰富的词典资源是一个表格(或电子表格),在每一行中含有一个词加一些性质。NLTK 中包括美国英语的CMU 发音词典,它是为语音合成器使用而设计的。

对每一个词,这个词典资源提供语音的代码——不同的声音不同的标签——叫做音素。
请看fire 有两个发音(美国英语中):单音节F AY1 R 和双音节F AY1 ER0。

比较词表

表格词典的另一个例子是比较词表。NLTK 中包含了所谓的斯瓦迪士核心词列表(Swadesh wordlists),几种语言中约200 个常用词的列表。

我们可以通过在entries()方法中指定一个语言链表来访问多语言中的同源词。

词汇工具:Toolbox

可能最流行的语言学家用来管理数据的工具是Toolbox,以前叫做Shoebox,因为它用满满的档案卡片占据了语言学家的旧鞋盒。一个Toolbox 文件由一个大量条目的集合组成,其中每个条目由一个或多个字段组成。大多数字段都是可选的或重复的,这意味着这个词汇资源不能作为一个表格或电子表格来处理。

WordNet

是面向语义的英语词典,类似与传统辞典,但具有更丰富的结构。NLTK 中包括英语WordNet,共有155,287 个词和117,659 个同义词集合。

2.4 WordNet
WordNet的层次结构:WordNet 的同义词集对应于抽象的概念,它们并不总是有对应的英语词汇。这些概念在层次结构中相互联系在一起。一些概念也很一般,如实体、状态、事件;这些被称为独一无二的根同义词集。其他的,如:油老虎和有仓门式后背的汽车等就比较具体的多。图2-8 展示了一个概念层次的一小部分。

图2-8. WordNet 概念层次片段:每个节点对应一个同义词集;边表示上位词/下位词关系,即上级概念与从属概念的关系。

更多的词汇关系:上位词和下位词被称为词汇关系,因为它们是同义集之间的关系。这个关系定位上下为“是一个”层次。WordNet 网络另一个重要的漫游方式是从物品到它们的部件(部分)或到它们被包含其中的东西(整体)。例如:一棵树的部分是它的树干,树冠等;这些都是part_meronyms()。一棵树的实质是包括心材和边材组成的,即substance_meronyms()。树木的集合形成了一个森林,即member_holonyms()。

语义相似度:我们已经看到同义词集之间构成复杂的词汇关系网络。给定一个同义词集,我们可以遍历WordNet 网络来查找相关含义的同义词集。知道哪些词是语义相关的,对索引文本集合非常有用,当搜索一个一般性的用语——例如:车辆——时就可以匹配包含具体用语——例如豪华轿车——的文档。回想一下每个同义词集都有一个或多个上位词路径连接到一个根上位词。连接到同一个根的两个同义词集可能有一些共同的上位词。如果两个同义词集共用一个非常具体的上位词——在上位词层次结构中处于较低层的上位词——它们一定有密切的联系。

2.5 小结
􀁺 文本语料库是一个大型结构化文本的集合。NLTK 包含了许多语料库,如:布朗语料库nltk.corpus.brown。
􀁺 有些文本语料库是分类的,例如通过文体或者主题分类;有时候语料库的分类会相互重叠。
􀁺 条件频率分布是一个频率分布的集合,每个分布都有一个不同的条件。它们可以用于通过给定内容或者文体对词的频率计数。
􀁺 行数较多的Python 程序应该使用文本编辑器来输入,保存为.py 后缀的文件,并使用import 语句来访问。
􀁺 Python 函数允许你将一段特定的代码块与一个名字联系起来,然后重用这些代码想用多少次就用多少次。
􀁺 一些被称为“方法”的函数与一个对象联系在起来,我们使用对象名称跟一个点然后跟方法名称来调用它,就像:x.funct(y)或者word.isalpha()。
􀁺 要想找到一些关于变量v 的信息,可以在Pyhon 交互式解释器中输入help(v)来阅读这一类对象的帮助条目。
􀁺 WordNet 是一个面向语义的英语词典,由同义词的集合—或称为同义词集(synsets)—组成,并且组织成一个网络。
􀁺 默认情况下有些函数是不能使用的,必须使用Python 的import 语句来访问。
3.加工原料文本

3.1 字符串:最底层的文本处理
我们侧重于将文本作为一个词链表。通过使用NLTK 中的语料库接口,我们可以忽略这些文本所在的文件。一个词的内容,一个文件的内容在编程语言中是由一个叫做字符串的基本数据类型来表示的。

3.2使用Unicode进行文字处理
Unicode 支持超过一百万种字符。每个字符分配一个编号,称为编码点。在Python 中,编码点写作\uXXXX 的形式,其中XXXX 是四位十六进制形式数。在一个程序中,我们可以像普通字符串那样操纵Unicode 字符串。然而,当Unicode 字符被存储在文件或在终端上显示,它们必须被编码为字节流。一些编码(如ASCII 和Latin-2)中每个编码点使用单字节,所以它们可以只支持Unicode 的一个小的子集就足够一种语言使用了。

文件中的文本都是有特定编码的,所以我们需要一些机制来将文本翻译成Unicode——翻译成Unicode 叫做解码。相对的,要将Unicode 写入一个文件或终端,我们首先需要将Unicode 转化为合适的编码——这种将Unicode 转化为其它编码的过程叫做编码。

3.3 使用正则表达式检测词组搭配
许多语言处理任务都涉及模式匹配。例如:我们可以使用endswith('ed')找到以“ed”结尾的词。

正则表达式给我们一个更加强大和灵活的方法描述我们感兴趣的字符模式,在Python 中使用正则表达式,需要使用import re 导入re 函数库。还需要一个用于搜索的词汇链表;我们再次使用词汇语料库,对它进行预处理消除某些名称。
>>> import re
>>> wordlist = [w for w in nltk.corpus.words.words('en') if w.islower()]

3.4 正则表达式的有益应用
使用re.search(regexp, w)匹配一些正则表达式regexp 来搜索词w。除了检查一个正则表达式是否匹配一个单词外,我们还可以使用正则表达式从词汇中提取的特征或以特殊的方式来修改词。

提取字符块

通过re.findall() (“find all”即找到所有)方法找出所有(无重叠的)匹配指定正则表达式的。让我们找出一个词中的元音,再计数它们:

查找词干

在使用网络搜索引擎时,我们通常不介意(甚至没有注意到)文档中的词汇与我们的搜索条件的后缀形式是否相同。查询“laptops”会找到含有“laptop”的文档,反之亦然。事实上,“laptop”与“laptops”只是字典中的同一个词(或词条)的两种形式。对于一些语言处理任务,我们想忽略词语结尾,只是处理词干。抽出一个词的词干的方法有很多种。

搜索已分词文本

你可以使用一种特殊的正则表达式搜索一个文本中多个词(这里的文本是一个标识符列表)。例如:“<a> <man>”找出文本中所有“a man”的实例。尖括号用于标记标识符的边界,尖括号之间的所有空白都被忽略(这只对NLTK 中的findall()方法处理文本有效)。

3.5 规范化文本

词干提取器

NLTK 中包括了一些现成的词干提取器,如果你需要一个词干提取器,你应该优先使用它们中的一个,而不是使用正则表达式制作自己的词干提取器,因为NLTK 中的词干提取器能处理的不规则的情况很广泛。

词性归并

词形归并
WordNet 词形归并器删除词缀产生的词都是在它的字典中的词。这个额外的检查过程使词形归并器比刚才提到的词干提取器要慢。

3.6 用正则表达式为文本分词
分词是将字符串切割成可识别的构成一块语言数据的语言单元。许多语料库已经分过词了,也因为NLTK中包括一些分词器。现在你已经熟悉了正则表达式,你可以学习如何使用它们来为文本分词,并对此过程中有更多的掌控权。

NLTK 的正则表达式分词器:函数nltk.regexp_tokenize()与re.findall()类似(我们一直在使用它进行分词)。然
而,nltk.regexp_tokenize()分词效率更高,且不需要特殊处理括号。为了增强可读性,我们将正则表达式分几行写,每行添加一个注释。特别的“(?x)”“verbose 标志”告诉Python 去掉嵌入的空白字符和注释。

>>> text = 'That U.S.A. poster-print costs $12.40...'
>>> pattern = r'''(?x) # set flag to allow verbose regexps
... ([A-Z]\.)+ # abbreviations, e.g. U.S.A.
... | \w+(-\w+)* # words with optional internal hyphens
... | \$?\d+(\.\d+)?%? # currency and percentages, e.g. $12.40, 82%
... | \.\.\. # ellipsis
... | [][.,;"'?():-_`] # these are separate tokens
... '''
>>> nltk.regexp_tokenize(text, pattern)
['That', 'U.S.A.', 'poster-print', 'costs', '$12.40', '...']

分词是一个比你可能预期的要更为艰巨的任务。没有单一的解决方案能在所有领域都行之有效,我们必须根据应用领域的需要决定那些是标识符。在开发分词器时,访问已经手工标注好的原始文本是有益的,这可以让你的分词器的输出结果与高品质(或称“黄金标准”)的标注进行比较。NLTK 语料库集合包括宾州树库的数据样本,包括《华尔街日报》原始文本(nltk.corpus.treebank_raw.raw())和分好词的版本(nltk.corpus.treebank.words())。

3.7 分割
分词是一个更普遍的分割问题的一个实例。在本节中,我们将看到这个问题的另外两个实例。

分句

在词级水平处理文本通常假定能够将文本划分成单个句子。一些语料库已经提供在句子级别的访问。在其他情况下,文本可能只是作为一个字符流。在将文本分词之前,我们需要将它分割成句子。NLTK 通过包含Punkt 句子分割器(Kiss & Strunk, 2006)简化了这些。

分词

对于一些书写系统,由于没有词边界的可视表示这一事实,文本分词变得更加困难。我们的第一个挑战仅仅是:我们需要找到一种方法来分开文本内容与分词标志。我们可以给每个字符标注一个布尔值来指示这个字符后面是否有一个分词标志(这个想法将在第7 章“分块”中大量使用)。让我们假设说话人会给语言学习者一个说话时的停顿,这往往是对应一个延长的暂停。这里是一种表示方法,包括初始的分词和最终分词目标。

现在分词的任务变成了一个搜索问题:找到将文本字符串正确分割成词汇的字位串。我们假定学习者接收词,并将它们存储在一个内部词典中。给定一个合适的词典,是能够由词典中的词的序列来重构源文本的。读过(Brent & Cart-wright, 1995)之后,我们可以定义一个目标函数,一个打分函数,我们将基于词典的大小和从词典中重构源文本所需的信息量尽力优化它的值。

如图计算目标函数:给定一个假设的源文本的分词(左),推导出一个词典和推导表,它能让源文本重构,然后合计每个词项(包括边界标志)与推导表的字符数,作为分词质量的得分;得分值越小表明分词越好。

图3-6. 计算目标函数:给定一个假设的源文本的分词(左),推导出一个词典和推导表,它能让源文本重构,然后合计每个词项(包括边界标志)与推导表的字符数,作为分词质量的得分;得分值越小表明分词越好。

4 分类和标注词汇

1. 什么是词汇分类,在自然语言处理中它们是如何使用?
2. 一个好的存储词汇和它们的分类的Python 数据结构是什么?
3. 我们如何自动标注文本中词汇的词类?

我们将介绍NLP 的一些基本技术,包括序列标注、N-gram 模型、回退和评估。这些技术在许多方面都很有用,标注为我们提供了一个表示它们的简单的上下文。我们还将看到标注为何是典型的NLP 流水线中继分词之后的第二个步骤。将词汇按它们的词性(parts-of-speech,POS)分类以及相应的标注它们的过程被称为词性标注(part-of-speech tagging, POS tagging)或干脆简称标注。词性也称为词类或词汇范畴。用于特定任务的标记的集合被称为一个标记集。我们在本章的重点是利用标记和自动标注文本。

4.1 使用词性标注器
一个词性标注器(part-of-speech tagger 或POS tagger)处理一个词序列,为每个词附加一个词性标记。
>>> text = nltk.word_tokenize("And now for something completely different")
>>> nltk.pos_tag(text)
[('And', 'CC'), ('now', 'RB'), ('for', 'IN'), ('something', 'NN'),('completely', 'RB'), ('different', 'JJ')]

4.2 标注语料库

表示已标注的标识符:按照NLTK 的约定,一个已标注的标识符使用一个由标识符和标记组成的元组来表示。

我们可以使用函数str2tuple()从表示一个已标注的标识符的标准字符串创建一个这样的特殊元组:
>>> tagged_token = nltk.tag.str2tuple('fly/NN')
>>> tagged_token
('fly', 'NN')

读取已标注的语料库:NLTK 中包括的若干语料库已标注了词性。

用文本编辑器打开一个布朗语料库的文件就能看到的例子:
The/at Fulton/np-tl County/nn-tl Grand/jj-tl Jury/nn-tl said/vbd Friday/nr an/at investigation/
nn of/in Atlanta’s/np$ recent/jj primary/nn election/nn produced/vbd / no/at
evidence/nn ''/'' that/cs any/dti irregularities/nns took/vbd place/nn ./.
其他语料库使用各种格式存储词性标记。NLTK 中的语料库阅读器提供了一个统一的接口,使你不必理会这些不同的文件格式。与刚才提取并显示的上面的文件不同,布朗语料库的语料库阅读器按如下所示的方式表示数据。注意:部分词性标记已转换为大写的;自从布朗语料库发布以来,这已成为标准的做法。

简化的词性标记集:已标注的语料库使用许多不同的标记集约定来标注词汇。

为了帮助我们开始,我们将看一看一个简化的部分标记集(表所示)。

未简化的标记
让我们找出每个名词类型中最频繁的名词。

例 中的程序找出所有以NN 开始的标记,并为每个标记提供了几个示例词汇。你会看到有许多名词的变种;最重要的含有$的名词所有格,含有S 的复数名词(因为复数名词通常以s 结尾),以及含有P 的专有名词。此外,大多数的标记都有后缀修饰符:-NC 表示引用,-HL 表示标题中的词,-TL 表示标题(布朗标记的特征)。

找出最频繁的名词标记的程序
def findtags(tag_prefix, tagged_text):
cfd = nltk.ConditionalFreqDist((tag, word) for (word, tag) in tagged_text
if tag.startswith(tag_prefix))
return dict((tag, cfd[tag].keys()[:5]) for tag in cfd.conditions())
>>> tagdict = findtags('NN', nltk.corpus.brown.tagged_words(categories='news'))
>>> for tag in sorted(tagdict):
... print tag, tagdict[tag]
...
NN ['year', 'time', 'state', 'week', 'man']
NN$ ["year's", "world's", "state's", "nation's", "company's"]
NN$-HL ["Golf's", "Navy's"]
NN$-TL ["President's", "University's", "League's", "Gallery's", "Army's"]
NN-HL ['cut', 'Salary', 'condition', 'Question', 'business'] ...

探索已标注的语料库

让我们简要地回过来探索语料库,我们在前面的章节中看到过,这次我们探索POS 标记。

假设我们正在研究词often,想看看它是如何在文本中使用的。我们可以试着看看跟在often 后面的词汇:
>>> brown_learned_text = brown.words(categories='learned')
>>> sorted(set(b for (a, b) in nltk.ibigrams(brown_learned_text) if a == 'often'))
[',', '.', 'accomplished', 'analytically', 'appear', 'apt', 'associated', 'assuming',
'became', 'become', 'been', 'began', 'call', 'called', 'carefully', 'chose', ...]
然而,它使用tagged_words()方法查看跟随词的词性标记可能更有指导性。
>>> brown_lrnd_tagged = brown.tagged_words(categories='learned', simplify_tags=True)
>>> tags = [b[1] for (a, b) in nltk.ibigrams(brown_lrnd_tagged) if a[0] == 'often']
>>> fd = nltk.FreqDist(tags)
>>> fd.tabulate()
VN V VD DET ADJ ADV P CNJ , TO VG WH VBZ .
15 12 8 5 5 4 4 3 3 1 1 1 1 1
请注意often 后面最高频率的词性是动词。名词从来没有在这个位置出现(在这个特别的语料中)。

4.3 自动标注
我们将看到一个词的标记依赖于这个词和它在句子中的上下文。

默认标注器:

最简单的标注器是为每个标识符分配同样的标记。这似乎是一个相当平庸的一步,但它建立了标注器性能的一个重要的底线。为了得到最好的效果,我们用最有可能的标记标注每个词。让我们找出哪个标记是最有可能的(现在使用未简化标记集):
>>> tags = [tag for (word, tag) in brown.tagged_words(categories='news')]
>>> nltk.FreqDist(tags).max()
'NN'

默认的标注器给每一个单独的词分配标记,即使是之前从未遇到过的词。碰巧的是,一旦我们处理了几千词的英文文本之后,大多数新词都将是名词。正如我们将看到的,这意味着,默认标注器可以帮助我们提高语言处理系统的稳定性。

正则表达式标注器:基于匹配模式分配标记给标识符。

例如:我们可能会猜测任一以ed结尾的词都是动词过去分词,任一以's 结尾的词都是名词所有格。可以用一个正则表达式的列表表示这些:
>>> patterns = [
... (r'.*ing$', 'VBG'), # gerunds
... (r'.*ed$', 'VBD'), # simple past
... (r'.*es$', 'VBZ'), # 3rd singular present
... (r'.*ould$', 'MD'), # modals
... (r'.*\'s$', 'NN$'), # possessive nouns
... (r'.*s$', 'NNS'), # plural nouns
... (r'^-?[0-9]+(.[0-9]+)?$', 'CD'), # cardinal numbers
... (r'.*', 'NN') # nouns (default)
... ]
>>> regexp_tagger = nltk.RegexpTagger(patterns)
>>> regexp_tagger.tag(brown_sents[3])
[('``', 'NN'), ('Only', 'NN'), ('a', 'NN'), ('relative', 'NN'), ('handful', 'NN'),
('of', 'NN'), ('such', 'NN'), ('reports', 'NNS'), ('was', 'NNS'), ('received', 'VBD'),
("''", 'NN'), (',', 'NN'), ('the', 'NN'), ('jury', 'NN'), ('said', 'NN'), (',', 'NN'),
('``', 'NN'), ('considering', 'VBG'), ('the', 'NN'), ('widespread', 'NN'), ...]
>>> regexp_tagger.evaluate(brown_tagged_sents)
0.20326391789486245

最终的正则表达式«.*»是一个全面捕捉的,标注所有词为名词。除了作为正则表达式标注器的一部分重新指定这个,这与默认标注器是等效的(只是效率低得多)。有没有办法结合这个标注器和默认标注器呢?我们将很快看到如何做到这一点。

查询标注器
很多高频词没有NN 标记。让我们找出100 个最频繁的词,存储它们最有可能的标记。然后我们可以使用这个信息作为“查找标注器”(NLTK UnigramTagger)的模型:

>>> fd = nltk.FreqDist(brown.words(categories='news'))
>>> cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news'))
>>> most_freq_words = fd.keys()[:100]
>>> likely_tags = dict((word, cfd[word].max()) for word in most_freq_words)
>>> baseline_tagger = nltk.UnigramTagger(model=likely_tags)
>>> baseline_tagger.evaluate(brown_tagged_sents)
0.45578495136941344

现在应该并不奇怪,仅仅知道100 个最频繁的词的标记就使我们能正确标注很大一部分
标识符(近一半,事实上)。让我们来看看它在一些未标注的输入文本上做的如何:
>>> sent = brown.sents(categories='news')[3]
>>> baseline_tagger.tag(sent)
[('``', '``'), ('Only', None), ('a', 'AT'), ('relative', None),
('handful', None), ('of', 'IN'), ('such', None), ('reports', None),
('was', 'BEDZ'), ('received', None), ("''", "''"), (',', ','),
('the', 'AT'), ('jury', None), ('said', 'VBD'), (',', ','),
('``', '``'), ('considering', None), ('the', 'AT'), ('widespread', None),
('interest', None), ('in', 'IN'), ('the', 'AT'), ('election', None),
(',', ','), ('the', 'AT'), ('number', None), ('of', 'IN'),
('voters', None), ('and', 'CC'), ('the', 'AT'), ('size', None),
('of', 'IN'), ('this', 'DT'), ('city', None), ("''", "''"), ('.', '.')]

许多词都被分配了一个None 标签,因为它们不在100 个最频繁的词之中。在这些情况下,我们想分配默认标记NN。换句话说,我们要先使用查找表,如果它不能指定一个标记就使用默认标注器,这个过程叫做回退。我们可以做到这个,通过指定一个标注器作为另一个标注器的参数,如下所示。现在查找标注器将只存储名词以外的词的词-标记对,只要它不能给一个词分配标记,它将会调用默认标注器。
>>> baseline_tagger = nltk.UnigramTagger(model=likely_tags,
... backoff=nltk.DefaultTagger('NN'))

评估

事实上,这些工具的性能评估是NLP 的一个中心主题。我们对比专家分配的标记来评估一个标注器的性能。由于我们通常很难获得专业和公正的人的判断,所以使用黄金标准测试数据来代替。这是一个已经手动标注并作为自动系统评估标准而被接受的语料库。当标注器对给定词猜测的标记与黄金标准标记相同,标注器被视为是正确的。

当然,设计和实施原始的黄金标准标注的也是人,更深入的分析可能会显示黄金标准中的错误,或者可能最终会导致一个修正的标记集和更复杂的指导方针。然而,黄金标准就目前有关的自动标注器的评估而言被定义成“正确的”。

开发一个已标注语料库是一个重大的任务。除了数据,它会产生复杂的工具、文档和实践,为确保高品质的标注。标记集和其他编码方案不可避免地依赖于一些理论主张,不是所有的理论主张都被共享。然而,语料库的创作者往往竭
尽全力使他们的工作尽可能理论中立,以最大限度地提高其工作的有效性。

4.4 N-gram标注

一元标注(Unigram Tagging)

一元标注器基于一个简单的统计算法:对每个标识符分配这个独特的标识符最有可能的标记。例如:它将分配标记JJ 给词frequent 的所有出现,因为frequent 用作一个形容词(例如:a frequent word)比用作一个动词(例如:I frequent this cafe)更常见。一个一元标注器的行为就像一个查找标注器,除了有一个更方便的建立它的技术,称为训练。

在下面的代码例子中,我们训练一个一元标注器,用它来标注一个句子,然后评估:
>>> from nltk.corpus import brown
>>> brown_tagged_sents = brown.tagged_sents(categories='news')
>>> brown_sents = brown.sents(categories='news')
>>> unigram_tagger = nltk.UnigramTagger(brown_tagged_sents)
>>> unigram_tagger.tag(brown_sents[2007])
[('Various', 'JJ'), ('of', 'IN'), ('the', 'AT'), ('apartments', 'NNS'),
('are', 'BER'), ('of', 'IN'), ('the', 'AT'), ('terrace', 'NN'), ('type', 'NN'),
(',', ','), ('being', 'BEG'), ('on', 'IN'), ('the', 'AT'), ('ground', 'NN'),
('floor', 'NN'), ('so', 'QL'), ('that', 'CS'), ('entrance', 'NN'), ('is', 'BEZ'),
('direct', 'JJ'), ('.', '.')]
>>> unigram_tagger.evaluate(brown_tagged_sents)
0.9349006503968017

我们训练一个UnigramTagger,通过在我们初始化标注器时指定已标注的句子数据作为参数。训练过程中涉及检查每个词的标记,将所有词的最可能的标记存储在一个字典里面,这个字典存储在标注器内部。

一般的 N-gram的标注

一个n-gram标注器是一个 unigram 标注器的一般化,它的上下文是当前词和它前面n-1 个标识符的词性标记。要选择的标记是圆圈里的tn,灰色阴影的是上下文。在图 所示的n-gram 标注器的例子中,我们让n= 3,也就是说,我们考虑当前词的前两个词的标记。一个n-gram 标注器挑选在给定的上下文中最有可能的标记。

1-gram 标注器是一元标注器(unigram tagger)另一个名称:即用于标注一个标识符的上下文的只是标识符本身。2-gram 标注器也称为二元标注器(bigram taggers),3-gram 标注器也称为三元标注器(trigram taggers)。

NgramTagger 类使用一个已标注的训练语料库来确定对每个上下文哪个词性标记最有可能。在这里,我们看到一个n-gram 标注器的特殊情况,即一个bigram 标注器。首先,我们训练它,然后用它来标注未标注的句子:
>>> bigram_tagger = nltk.BigramTagger(train_sents)
>>> bigram_tagger.tag(brown_sents[2007])
[('Various', 'JJ'), ('of', 'IN'), ('the', 'AT'), ('apartments', 'NNS'),
('are', 'BER'), ('of', 'IN'), ('the', 'AT'), ('terrace', 'NN'),
('type', 'NN'), (',', ','), ('being', 'BEG'), ('on', 'IN'), ('the', 'AT'),
('ground', 'NN'), ('floor', 'NN'), ('so', 'CS'), ('that', 'CS'),
('entrance', 'NN'), ('is', 'BEZ'), ('direct', 'JJ'), ('.', '.')]
>>> unseen_sent = brown_sents[4203]
>>> bigram_tagger.tag(unseen_sent)
[('The', 'AT'), ('population', 'NN'), ('of', 'IN'), ('the', 'AT'), ('Congo', 'NP'),
('is', 'BEZ'), ('13.5', None), ('million', None), (',', None), ('divided', None),
('into', None), ('at', None), ('least', None), ('seven', None), ('major', None),
('``', None), ('culture', None), ('clusters', None), ("''", None), ('and', None),
('innumerable', None), ('tribes', None), ('speaking', None), ('400', None),
('separate', None), ('dialects', None), ('.', None)]

请注意,bigram 标注器能够标注训练中它看到过的句子中的所有词,但对一个没见过的句子表现很差。只要遇到一个新词,就无法给它分配标记。它不能标注下面的词(如:million),即使是在训练过程中看到过的,只是因为在训练过程中从来没有见过它前面有一个None 标记的词。因此,标注器标注句子的其余部分也失败了。它的整体准确度
得分非常低:
>>> bigram_tagger.evaluate(test_sents)
0.10276088906608193

当n 越大,上下文的特异性就会增加,我们要标注的数据中包含训练数据中不存在的上下文的几率也增大。这被称为数据稀疏问题,在NLP 中是相当普遍的。因此,我们的研究结果的精度和覆盖范围之间需要有一个权衡(这与信息检索中的精度/召回权衡有关)。

注意:
N-gram 标注器不应考虑跨越句子边界的上下文。因此,NLTK 的标注器被设计用于句子链表,一个句子是一个词链表。在一个句子的开始,tn-1和前面的标记被设置为None。

组合标注器:解决精度和覆盖范围之间的权衡的一个办法是尽可能的使用更精确的算法,但却在很多时候落后于具有更广覆盖范围的算法。例如:我们可以按如下方式组合bigram 标注器、unigram 标注器和一个默认标注器:

1. 尝试使用bigram 标注器标注标识符。
2. 如果bigram 标注器无法找到一个标记,尝试unigram 标注器。
3. 如果unigram 标注器也无法找到一个标记,使用默认标注器。

大多数NLTK 标注器允许指定一个回退标注器。回退标注器自身可能也有一个回退标注器:
>>> t0 = nltk.DefaultTagger('NN')
>>> t1 = nltk.UnigramTagger(train_sents, backoff=t0)
>>> t2 = nltk.BigramTagger(train_sents, backoff=t1)
>>> t2.evaluate(test_sents)
0.84491179108940495

标注生词:我们标注生词的方法仍然是回退到一个正则表达式标注器或一个默认标注器,这些都无法利用上下文。

因此,如果我们的标注器遇到词blog,训练过程中没有看到过,它会分配相同的标记,不论这个词出现的上下文是the blog 还是to blog。

一个有用的基于上下文标注生词的方法是限制一个标注器的词汇表为最频繁的n 个词,使用5.3 节中的方法替代每个其他的词为一个特殊的词UNK。训练时,一个unigram 标注器可能会学到UNK 通常是一个名词。然而,n-gram 标注器会检测它的一些其他标记中的上下文。例如:如果前面的词是to(标注为TO),那么UNK 可能会被标注为一个动词。

存储标注器

在大语料库上训练一个标注器可能需要大量的时间,一个训练好的标注器保存到一个文件以后重复使用。

跨句子边界标注

一个n-gram 标注器使用最近的标记作为为当前的词选择标记的指导。当标记一个句子的第一个词时,trigram 标注器将使用前面两个标识符的词性标记,这通常会是前面句子的最后一个词和句子结尾的标点符号。然而,在前一句结尾的词的类别与下一句的开头的通常没有关系。为了应对这种情况,我们可以使用已标注句子的链表来训练、运行和评估标注器,如例 所示。

例. 句子层面的N-gram 标注
brown_tagged_sents = brown.tagged_sents(categories='news')
brown_sents = brown.sents(categories='news')
size = int(len(brown_tagged_sents) * 0.9)
train_sents = brown_tagged_sents[:size]
test_sents = brown_tagged_sents[size:]
t0 = nltk.DefaultTagger('NN')
t1 = nltk.UnigramTagger(train_sents, backoff=t0)
t2 = nltk.BigramTagger(train_sents, backoff=t1)
>>> t2.evaluate(test_sents)
0.84491179108940495

4.5 基于转换的标注
Brill 标注是一种基于转换的学习,一般的想法很简单:猜每个词的标记,然后返回和修复错误的。在这种方式中,Brill 标注器陆续将一个不良标注的文本转换成一个更好的。与n-gram 标注一样,这是有监督的学习方法,因为我们需要已标注的训练数据来评估标注器的猜测是否是一个错误。然而,不像n-gram 标注,它不计数观察结果,只编制一个转换修正规则链表。

让我们看看下面的例子:
(1) The President said he will ask Congress to increase grants to states for vocational rehabilitation.
我们将研究两个规则的运作:
(a)当前面的词是TO 时,替换NN 为VB;
(b)当下一个标记是NNS 时,替换TO 为IN 。
下表说明了这一过程,首先使用unigram 标注器标注,然后运用规则修正错误。

Brill 标注器的另一个有趣的特性:规则是语言学可解释的。与采用潜在的巨大的n-gram 表的n-gram 标注器相比,我们并不能从直接观察这样的一个表中学到多少东西,而Brill标注器学到的规则可以。

4.6 如何确定一个词的分类
在一般情况下,语言学家使用形态学、句法和语义线索确定一个词的类别。

形态学线索

一个词的内部结构可能为这个词分类提供有用的线索。举例来说:-ness 是一个后缀,与形容词结合产生一个名词,如happy→happiness,ill→illness。因此,如果我们遇到的一个以-ness 结尾的词,很可能是一个名词。同样的,-ment 是与一些动词结合产生一个名词的后缀,如govern→government 和establish→establishment。

英语动词也可以是形态复杂的。例如:一个动词的现在分词以-ing 结尾,表示正在进行的还没有结束的行动(如:falling,eating)的意思。-ing 后缀也出现在从动词派生的名词中,如:the falling of the leaves(这被称为动名词)。

句法线索
另一个信息来源是一个词可能出现的典型的上下文语境。

例如:假设我们已经确定了名词类。那么我们可以说,英语形容词的句法标准是它可以立即出现在一个名词前,或紧跟在词be 或very 后。根据这些测试,near 应该被归类为形容词:

a. the near window
b. The end is (very) near.

语义线索
最后,一个词的意思对其词汇范畴是一个有用的线索。

例如:名词的众所周知的一个定义是根据语义的:“一个人、地方或事物的名称。”在现代语言学,词类的语义标准受到怀疑,主要是因为它们很难规范化。然而,语义标准巩固了我们对许多词类的直觉,使我们能够在不熟悉的语言中很好的猜测词的分类。例如:如果我们都知道荷兰语词verjaardag 的意思与英语词birthday 相同,那么我们可以猜测verjaardag 在荷兰语中是一个名词。然而,一些修补是必要的:虽然我们可能翻译zij is vandaag jarig as it ’s her birthday today,词jarig在荷兰语中实际上是形容词,与英语并不完全相同。

新词
所有的语言都学习新的词汇。最近添加到牛津英语词典中的一个单词列表包括cyberslacker、fatoush、blamestorm、SARS、cantopop、bupkis、noughties、muggle 和robata。请注意,所有这些新词都是名词,这反映在名词被称为开放类。相反,介词被认为是一个封闭类。也就是说,只有有限的词属于这个类别(例如:above、along、at、below、beside、between、during、for、from、in 、near、on、outside、over、past、through、towards、under、up、with),词类成员随着很长时间的推移才逐渐改变。

词性标记集中的形态学
普通标记集经常捕捉一些构词信息,即词借助它们的句法角色获得的一种形态标记的信息。

例如:下面句子中词go 的不同语法形式的选集:
a. Go away!
b. He sometimes goes to the cafe.
c. All the cakes have gone.
d. We went on the excursion.
这些形态中的每一个——go、goes、gone 和went——是形态学上的区别。思考形式goes。它出现在受限制的语法环境中,需要一个第三人称单数的主语。因此,下面的句子是不合语法的。

更细粒度的标记集提供有关这些形式的有用信息,可以帮助尝试检测标记序列模式的其它处理者。布朗标记集捕捉这些区别,如表中的总结:

除了这组动词标记,动词to be 的各种形式也有特殊的标记:be/BE,being/BEG,am/BEM,are/BER,is/BEZ,been/BEN,were/BED 和was/BEDZ(加上额外的动词否定形式的标记)。总的来说,这种动词细粒度标记意味着使用此标记集的自动标注器能有效开展有限数量的形态分析。

大多数词性标注集使用相同的基本类别,然而,标记集的相互区别不仅在于它们如何细致的将词分类,也在于它们如何界定其类别。例如:is 在一个标记集可能会被简单的标注为动词,而在另一个标记集中被标注为lexeme be 的不同形式(如在布朗语料库中)。这种标记集的变化是不可避免的,因为词性标记被以不同的方式用于不同的任务。换句话说,没有一个“正确的方式”来分配标记,只有根据目标不同或多或少有用的方法。

4.7 小结
􀁺 词可以组成类,如名词、动词、形容词以及副词。这些类被称为词汇范畴或者词性。词性被分配短标签或者标记,如NN 和VB。
􀁺 给文本中的词自动分配词性的过程称为词性标注、POS 标注或只是标注。
􀁺 自动标注是NLP 流程中重要的一步,在各种情况下都十分有用,包括预测先前未见过的词的行为、分析语料库中词的使用以及文本到语音转换系统。
􀁺 一些语言学语料库,如布朗语料库,已经做了词性标注。
􀁺 有多种标注方法,如默认标注器、正则表达式标注器、unigram 标注器、n-gram 标注器。这些都可以结合一种叫做回退的技术一起使用。
􀁺 标注器可以使用已标注语料库进行训练和评估。
􀁺 回退是一个组合模型的方法:当一个较专业的模型(如bigram 标注器)不能为给定内容分配标记时,我们回退到一个较一般的模型(如unigram 标注器)
􀁺 词性标注是NLP 中一个重要的早期的序列分类任务:利用局部上下文语境中的词和标记对序列中任意一点的分类决策。
􀁺 字典用来映射任意类型之间的信息,如字符串和数字:freq['cat']=12。我们使用大括号来创建字典:pos = {},pos = {'furiously': 'adv', 'ideas': 'n', 'colorless':'adj'}。
􀁺 N-gram 标注器可以定义较大数值的n,但是当n 大于3 时,我们常常会面临数据稀疏问题;即使使用大量的训练数据,我们看到的也只是可能的上下文的一小部分。
􀁺 基于转换的标注学习一系列“改变标记s 为标记t 在上下文c 中”形式的修复规则,每个规则会修复错误,也可能引入(较小的)错误。

-------

一.分词软件简介

分词算法在20世纪80年代就有研究,不过基于当时的技术条件所限,大多数就是原始的机械分词算法。比如,最大匹配算法,mmseg等。关于原始的机械分词算法 http://www.cnblogs.com/alic/articles/1215001.html 这篇blog有很详细的介绍。

之后随着统计算法在自然语言处理领域地位的奠定以及机器学习的兴起,基于统计和机器学习的分词算法逐渐成为主流。根据机器学习方法的分类,分词算法也可以分成无监督分词,半监督分词以及有监督的分词。目前有监督的分词以及半监督的分词已经研究的比较成熟。对于这种分词算法,大致可以分为四类:

第一类是生成式的基于词的分词方法,这类具有代表的是中科院的ICTCLAS等等比较经典的分词软件。

第二类是判别式的基于词的分词方法,这类中的算法比较少,其中一个是基于平衡感知机的分词。

第三类是生成式基于字的生成式分词方法,比如Wang(2009)所提出的n元模型分词算法。

第四类也是目前主流的是基于字的判别式分词方法,主要是最大熵模型和条件随机场模型。几乎全部2003年之后提出的分词算法都与这一类别有关,比如哈工大的LTP和Stanford Word Segmenter就是采用CRF模型。

此外,分词算法还可以根据在自然预言处理中的步骤来分,比如纯分词,就是除了分词之外什么都不做,大多数基于字的分词算法都属于这一类。此外将分词和词性标注结合在一起完成,比如ICTCLAS。还有基于语义网络分词的算法。总的来说,结合额外信息越多,对于分词结果就越好。比如ICTCLAS将分词与词性标注结果结合起来,效果就比光光使用一元概率模型(ICTCLAS)效果要好。

分词模型

分词模型大致可以分为判别式和生成式,以及基于词和基于字的方法。主要使用到的模型为: n-Gram,Percepton,HMM,SVM,ME,CRF。判别式和生成式的区别就是判别式是计算P(Y|X)的条件概率,但是生成式则是计算P(X1, X2)的联合概率,通常来说判别式的效果要比生成式的要好,这一分类比较复杂,不好解释,涉及到很多数学模型,详情可以去看看相关资料。

基于词和基于字的分词的区别就是基于词的算法将词看成算法中最小单元,比如这句话


结合/成/分子/时


在基于词的分词算法中,主要用到一个词典,“结合”、“成”、“分子”在词典中,它们是分词中的最小单元,不可拆分,一旦拆分就会出现分词错误。但是基于字的分词算法则不同,它将每个字看成是一个单元,通常和序列标注相结合,对每个字进行标注,然后得出分词结果。比如


结合成分子时


使用CRF等序列标注模型得出的序列标注结果是


B E S B E S


其中B表示一个词的开头,E表示一个词的结尾,S表示单个字作为词。然后分词的结果经过一些小处理就可以得出了。

通常来说基于词的分词算法在词典比较全,文章比较正式的时候效果比较好。但是总是会遇见一些比较变态的词典中没有的词,其中最有代表的就是人名地名还有商标名等等。所以一般这些基于词分词软件还必须要加上识别人名地名的功能。

基于字的分词算法主要是依赖于某些字在构词方面的特征,比如“的”字通常就是单个字出现,有很大的几率是标注S,“化”字比较喜欢出现在词的末尾,比如现代化,工业化等等。根据这些信息进行标注分词,它对于词典中不存在的词效果识别几率比较大,但是对于词典中的词可能会识别错误,另外还会出现千奇百怪的分词错误,比如“沙把”等等。 因此,现在多数的分词软件在基于字的基于上,或多或少的结合了一点基于词的特征。

二.实现中文分词的18种分词工具

由于中文文本词与词之间没有像英文那样有空格分隔,因此很多时候中文文本操作都涉及切词,这里整理了一些。一般来说用CRF实现的分词工具的处理速度是比较慢的(训练CRF模型是非常耗时的),但是精度高,涉及CRF的分词工具有CRF++,Stanford分词工具。

Bakeoff是一个国际中文处理比赛,有多个语料,所以每个语料都有排名。只有部分优秀的Bakeoff工具开源,以下介绍以下18种分词工具(大部分是基于java语言):

Stanford 汉语分词工具

官网:http://nlp.stanford.edu/software/segmenter.shtmlStanford 汉语分词工具的成绩:2005年Bakeoff2两个语料的测试第一。Stanford 汉语分词工具

一篇使用介绍:http://hi.baidu.com/liheming333/item/585fba1f898838623e87ce18

斯坦福自然语言小组直接使用CRF 的方法,特征窗口为5。

哈工大语言云(LTP -cloud)

项目网址:http://www.ltp-cloud.com/download/#ltp_cloud_sdk

HIT的ITNLP Lab, HIT Wei JIANG在Bakeoff 2005的open语料MSR上获得测评第一名。语言云曾获CoNLL2009七国语言句法语义分析评测总成绩第一名,使用方式为web service。

语言云(语言技术平台云 LTP-Cloud)是由哈工大社会计算与信息检索研究中心研发的云端自然语言处理服务平台。 后端依托于语言技术平台,语言云为用户提供了包括分词、词性标注、依存句法分析、命名实体识别、语义角色标注在内的丰富高效的自然语言处理服务。

作为基于云端的服务,语言云具有如下一些优势:

免安装:用户只需要下载语言云客户端源代码,编译执行后即可获得分析结果,无需调用静态库或下载模型文件。

省硬件:语言云客户端几乎可以运行于任何硬件配置的计算机上,用户不需要购买高性能的机器,即可快捷的获得分析结果。

跨平台:语言云客户端几乎可以运行于任何操作系统之上,无论是Windows、Linux各个发行版或者Mac OS。

跨编程语言:时至今日,语言云已经提供了包括C++,Java,C#,Python,Ruby在内的客户端,其他编程语言的客户端也在开发之中。

在运算资源有限,编程语言受限的情况下,语言云无疑是用户进行语言分析更好的选择。
从2006年9月5日开始该平台对外免费共享目标代码,截止目前,已经有国内外400多家研究单位共享了LTP,也有国内外多家商 业公司购买了LTP,用于实际的商业项目中。2011年6月1日,为了与业界同行共同研究和开发中文信息处理核心技术,正式将LTP的源代码对外共享,LTP由C++语言开发,可运行于Windows和Linux操作系统。

ICTCLAS: 汉语词法分析系统

官网:http://ictclas.nlpir.org/ Author:中国科学院计算技术研究所

ICTCLAS(Institute of Computing Technology, Chinese Lexical Analysis System)获取Bakeoff 1两项第一。这是最早的中文开源分词项目之一,ICTCLAS在国内973专家组组织的评测中活动获得了第一名,在第一届(2003)国际中文处理研究机构SigHan组织的评测中都获得了多项第一名。

性能:分词速度单机996KB/s, API 不超过 200KB ,各种词典数据压缩后不到 3M.

准确率:分词精度98.45%

语言和平台:ICTCLAS全部采用 C/C++ 编写,支持 Linux 、 FreeBSD 及 Windows 系列操作系统,支持 C/C++ 、 C# 、 Delphi、 Java 等主流的开发语言。

主要功能:中文分词;词性标注;命名实体识别;新词识别;同时支持用户词典;支持繁体中文;支持GBK 、 UTF-8 、 UTF-7 、 UNICODE 等多种编码格式。

算法:完美PDAT 大规模知识库管理技术( 200510130690.3 ),在高速度与高精度之间取得了重大突破,该技术可以管理百万级别的词典知识库,单机每秒可以查询 100 万词条,而内存消耗不到知识库大小的 1.5 倍。层叠隐马尔可夫模型( Hierarchical Hidden Markov Model ) ,该分词系统的主要是思想是先通过 CHMM( 层叠形马尔可夫模型 ) 进行分词 , 通过分层 , 既增加了分词的准确性 , 又保证了分词的效率 . 共分五层, 如下图所示。基本思路是进行原子切分 , 然后在此基础上进行N- 最短路径粗切分 , 找出前 N 个最符合的切分结果 , 生成二元分词表 , 然后生成分词结果 , 接着进行词性标注并完成主要分词步骤 .

Ansj(ICTCLAS的java实现)

项目网址:https://github.com/ansjsun/ansj_seg

作者网址:http://www.ansj.org/

ansj分词.ict的真正java实现.分词效果速度都超过开源版的ict.中文分词,人名识别,词性标注,用户自定义词典增加了对lucene的支持.如果不想编译文件可以直接到 https://github.com/ansjsun/mvn-repo/tree/gh-pages/org/ansj这里下载jar包!

这是一个ictclas的java实现.基本上重写了所有的数据结构和算法.词典是用的开源版的ictclas所提供的.并且进行了部分的人工优化。

性能:内存中中文分词每秒钟大约100万字(速度上已经超越ictclas),文件读取分词每秒钟大约30万字

正确率:准确率能达到96%以上

功能:目前实现了.中文分词. 中文姓名识别 . 用户自定义词典可以应用到自然语言处理等方面,适用于对分词效果要求搞的各种项目.

庖丁解牛分词

官网:http://code.google.com/p/paoding/

语言和平台:Java,提供 lucence 3.0 接口,仅支持 Java 语言。

性能:在PIII 1G 内存个人机器上, 1 秒 可准确分词 100 万 汉字。

算法:采用基于 不限制个数 的词典文件对文章进行有效切分

主要功能:使能够将对词汇分类定义。能够对未知的词汇进行合理解析

盘古分词

官网:http://pangusegment.codeplex.com

博客:http://www.cnblogs.com/eaglet/

是一个中英文分词组件。Pan Gu Segment is alibrary that can segment Chinese and English words from sentence.盘古分词是一个中英文分词组件。作者eaglet 曾经开发过KTDictSeg 中文分词组件,拥有大量用户。作者基于之前分词组件的开发经验,结合最新的开发技术重新编写了盘古分词组件。

主要功能:中文分词功能,中文未登录词识别,词频优先, 盘古分词可以根据词频来解决分词的歧义问题, 多元分词, 盘古分词提供多重输出解决分词粒度和分词精度权衡的问题, 中文人名识别, 强制一元分词, 繁体中文分词, 同时输出简体和繁体 中文词性输出 盘古分词可以将以登录词的中文词性输出给用户,以方便用户做进一步处理, 全角字符支持, 盘古分词可以识别全角的字母和数字, 英文分词, 英文专用词识别(一些英文简写是字母符号混合,或者是字母数字混合,这个分词起来就不能按照空格符号这样分割了,对于字母符号混合的如 U.S.A ,只要将这个词录入到字典中,盘古分词就可以分出整词。对于字母和数字混合的,盘古分词会自动作为整词输出),英文原词输出,英文大小写同时输出。

其他功能:

停用词过滤:对于一些标点符号,连词,助词等有时候需要在分词时过滤掉,盘古分词提供一个 StopWord.txt 文件,用户只要将需要过滤的词加入到这个文件中,并将停用词过滤开发打开,就可以过滤掉这些词。

设置分词权值:盘古分词可以让用户对如下特性设置自定义权值,1 未登录词权值 2 最匹配词权值 3 次匹配词权值 4 再次匹配词权值 5 强行输出的单字的权值 6 数字的权值 7 英文词汇权值 8 符号的权值 9 强制同时输出简繁汉字时,非原来文本的汉字输出权值。

用户自定义规则:

字典管理,盘古分词提供一个字典管理工具 DictManage 通过这个工具,你可以增加,修改,和删除字典中的单词

动态加载字典,通过字典工具增加,修改,和删除字典中的单词后,保持字典,盘古分词会自动将新的字典文件加载进去,而不需要重新启动。

关键词高亮组件,Lucene 提供了一个关键词高亮组件,但这个组件对中文的支持不是特别好,特别是如果还有多元分词的情况,处理的就更不好。盘古分词提供了一个针对中文和英文的关键词高亮组件 PanGu.HighLight ,其对中文的支持要好于Lucene 那个高亮组件。

同义词输出( 后续版本提供 ),Lucene.net 接口及示例等在PanGu4Lucene 这个包里面有我做的一个盘古 +Lucene 的简单新闻搜索 Web 示例程序, Release 包里面有使用说明。

性能:Core Duo 1.8 GHz 下单线程 分词速度为 390K 字符每秒, 2 线程分词速度为 690K 字符每秒。

算法:盘古分词提供的字典包括17万个中文常用单词,但这个字典依然不够完整,如果要分词更准确,需要适当维护一下这个字典。中文人名的识别能力取决于 ChsSingleName.txt , ChsDoubleName1.txt , ChsDoubleName2.txt 这三个文件,它们分别表示单子人名,双字人名的首字和双字人名的尾字。

IKAnalyzer

官网:http://code.google.com/p/ik-analyzer/

作者博客:http://linliangyi2007.iteye.com/

从2006年12月推出1.0版开始。开源轻量级的包语言和平台:基于java 语言开发 , 最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的 IKAnalyzer3.0 则发展为面向 Java 的公用分词组件,独立于 Lucene 项目,同时提供了对 Lucene 的默认优化实现。

算法:采用了特有的“ 正向迭代最细粒度切分算法 “ 。采用了多子处理器分析模式,支持:英文字母( IP 地址、 Email 、 URL )、数字(日期,常用中文数量词,罗马数字,科学计数法),中文词汇(姓名、地名处理)等分词处理。优化的词典存储,更小的内存占用。支持用户词典扩展定义。针对 Lucene 全文检索优化的查询分析器 IKQueryParser ;采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高 Lucene 检索的命中率。

性能:在系统环境:Core2i7 3.4G双核,4G内存,window 7 64位, Sun JDK 1.6_29 64位 普通pc环境测试,IK2012具有160万字/秒(3000KB/S)的高速处理能力

imdict-chinese-analyzer

官网:http://code.google.com/p/imdict-chinese-analyzer/是imdict 智能词典的智能中文分词模块,ictclas4j中文分词系统是 sinboy 在中科院张华平和刘群老师的研制的 FreeICTCLAS 的基础上完成的一个 java 开源分词项目,简化了原分词程序的复杂度,旨在为广大的中文分词爱好者一个更好的学习机会。

算法 :基于隐马尔科夫模型(Hidden Markov Model, HMM) ,是中国科学院计算技术研究所的 ictclas 中文分词程序的重新实现(基于 Java ),可以直接为lucene搜索引擎提供简体中文分词支持 。

主要功能:

1, 完全 Unicode 支持,分词核心模块完全采用Unicode 编码,无须各种汉字编码的转换,极大的提升了分词的效率。2. 提升搜索效率,根据imdict 智能词典的实践,在有智能中文分词的情况下,索引文件比没有中文分词的索引文件小 1/3

3. 提高搜索准确度,imdict-chinese-analyzer采用了 HHMM 分词模型,极大的提高了分词的准确率,在此基础上的搜索,比对汉字逐个切分要准确得多!

4. 更高效的数据结构,为了提高效率,针对常用中文检索的应用场景,imdict-chinese-analyzer 对一些不必要的功能进行了删减,例如词性标注、人名识别、时间识别等等。另外还修改了算法的数据结构,在内存占用量缩减到 1/3 的情况下把效率提升了数倍。imdict-chinese-analyzer的分词效率与 C ++实现的 ICTCLAS 3.0的分词效率在同一个数量级,是 ictclas4j 的 36 倍!

mmseg4j

项目网址:(旧)http://code.google.com/p/mmseg4j/

(新)https://github.com/chenlb/mmseg4j-solr

作者博客:http://blog.chenlb.com/ http://chenlb.iteye.com/
算法:

1、mmseg4j 用 Chih-Hao Tsai 的 MMSeg 算法(http://technology.chtsai.org/mmseg/)实现的中文分词器,并实现 lucene 的 analyzer和 solr 的TokenizerFactory 以方便在Lucene和Solr中使用。

2、MMSeg 算法有两种分词方法:Simple和Complex,都是基于正向最大匹配。Complex 加了四个规则过虑。官方(指mmseg论文的作者)说:词语的正确识别率达到了 98.41%。

mmseg4j 已经实现了这两种分词算法。

1.5版的分词速度simple算法是 1100kb/s左右、complex算法是 700kb/s左右,(测试机:AMD athlon 64 2800+ 1G内存 xp)。
1.6版在complex基础上实现了最多分词(max-word)。“很好听” -> “很好|好听”; “中华人民共和国” -> “中华|华人|共和|国”; “中国人民银行” -> “中国|人民|银行”。
1.7-beta 版, 目前 complex 1200kb/s左右, simple 1900kb/s左右, 但内存开销了50M左右. 上几个版都是在10M左右.
1.8 后,增加 CutLetterDigitFilter过虑器,切分“字母和数”混在一起的过虑器。比如:mb991ch 切为 “mb 991 ch”。

mmseg4j实现的功能详情请看:http://mmseg4j.googlecode.com/svn/trunk/CHANGES.txt

FudanNLP(复旦大学)
官网:http://code.google.com/p/fudannlp/
2013.8.14 发布FudanNLP1.6.1版。时常更新。复旦大学开发的软件。FudanNLP主要是为中文自然语言处理而开发的工具包,也包含为实现这些任务的机器学习算法和数据集。本工具包及其包含数据集使用LGPL3.0许可证。开发语言为Java。功能包括中文分词等,不需要字典支持。
功能:
信息检索: 文本分类 新闻聚类
中文处理: 中文分词 词性标注 实体名识别 关键词抽取 依存句法分析 时间短语识别
结构化学习: 在线学习 层次分类 聚类 精确推理

Jcseg

官网:http://code.google.com/p/jcseg/

jcseg是使用Java开发的一个中文分词器,使用mmseg算法实现。目前最高版本:jcseg1.9.0。兼容最高版本lucene-4.x和最高版本solr-4.x

主要特性:

mmseg四种过滤算法,分词准确率达到了98.41%。

支持自定义词库。在lexicon文件夹下,可以随便添加/删除/更改词库和词库内容,并且对词库进行了分类。如何给jcseg添加词库/新词

中英文同义词追加/同义词匹配 + 中文词条拼音追加.词库整合了《现代汉语词典》和cc-cedict辞典中的词条,并且依据cc-cedict词典为词条标上了拼音,依据《中华同义词词 典》为词条标上了同义词(尚未完成)。更改jcseg.properties配置文档可以在分词的时候加入拼音和同义词到分词结果中。

中文数字和中文分数识别,例如:”一百五十个人都来了,四十分之一的人。”中的”一百五十”和”四十分之一”。并且jcseg会自动将其转换为阿拉伯数字加入到分词结果中。如:150, 1/40。

支持中英混合词和英中混合词的识别(维护词库可以识别任何一种组合)。例如:B超, x射线, 卡拉ok, 奇都ktv, 哆啦a梦。

更好的英文支持,电子邮件,网址,小数,分数,百分数,字母和标点组合词(例如C++, c#)的识别。(这个对购物网址来说很重要)。

支持阿拉伯数字/小数/中文数字基本单字单位的识别,例如2012年,1.75米,38.6℃,五折,并且jcseg会将其转换为“5折”加入分词结果中。

智能圆角半角, 英文大小写转换;特殊字母识别:例如:Ⅰ,Ⅱ;特殊数字识别:例如:①,⑩

配对标点内容提取:例如:最好的Java书《java编程思想》,‘畅想杯黑客技术大赛’,被《,‘,“,『标点标记的内容。(1.6.8版开始支持)。

智能中文人名识别。中文人名识别正确率达94%以上。(可以维护lex-lname.lex,lex-dname-1.lex,lex-dname-2.lex来提高准确率),(引入规则和词性后会达到98%以上的识别正确率)。

自动中英文停止词过滤功能(需要在jcseg.properties中开启该选项,lex-stopwords.lex为停止词词库)。

词库更新自动加载功能, 开启一个守护线程随时检测词库的更新并且加载。

自动词性标注。

分词速度:

测试环境:2.8GHZ/2G/Ubuntu

Simple 模式: 1366058字/秒 3774.5KB/秒

Complex 模式: 479338字/秒 1324.4KB/秒

分词正确率98%以上,请参考本算法的原作:http://technology.chtsai.org/mmseg/

测试文章,“世界与和平” 简易模式830msec,复杂模式2461msec。

SCWS

算法:基于词频词典的机械中文分词引擎,采用的是采集的词频词典,并辅以一定的专有名称,人名,地名,数字年代等规则识别来达到基本分词

准确率:经小范围测试大概准确率在 90% ~ 95% 之间,已能基本满足一些小型搜索引擎、关键字提取等场合运用。

性能:45Kb左右的文本切词时间是 0.026 秒,大概是 1.5MB 文本 / 秒,

语言和平台:SCWS 采用纯 C 代码开发,以 Unix-Like OS 为主要平台环境,提供共享函数库,方便植入各种现有软件系统。此外它支持 GBK , UTF-8 ,BIG5 等汉字编码。支持 PHP4 和PHP 5 。

版本列表

Friso

官网http://code.google.com/p/friso/

friso是使用c语言开发的一个中文分词器,使用流行的mmseg算法实现。完全基于模块化设计和实现,可以很方便的植入到其他程序中,例如:MySQL,PHP等。并且提供了一个php中文分词扩展robbe。

特性:

只支持UTF-8编码。【源码无需修改就能在各种平台下编译使用,加载完20万的词条,内存占用稳定为14M。】。

mmseg四种过滤算法,分词准确率达到了98.41%。

支持自定义词库。在dict文件夹下,可以随便添加/删除/更改词库和词库词条,并且对词库进行了分类。

词库使用了friso的Java版本jcseg的简化词库。

支持中英混合词的识别。例如:c语言,IC卡。

很好的英文支持,电子邮件,网址,小数,分数,百分数。

支持阿拉伯数字基本单字单位的识别,例如2012年,5吨,120斤。

自动英文圆角/半角,大写/小写转换。并且具有很高的分词速度:简单模式:3.7M/秒,复杂模式:1.8M/秒。

HTTPCWS:

PHPCWS 是一款开源的 PHP 中文分词扩展,目前仅支持 Linux/Unix 系统。

算法:PHPCWS 先使用“ICTCLAS 3.0 共享版中文分词算法 ” 的 API 进行初次分词处理,再使用自行编写的 “ 逆向最大匹配算法 ” 对分词和进行词语合并处理,并增加标点符号过滤功能,得出分词结果。 ICTCLAS 3.0 商业版是收费的,而免费提供的 ICTCLAS 3.0 共享版不开源,词库是根据人民日报一个月的语料得出的,很多词语不存在。所以本人对 ICTCLAS 分词后的结果,再采用逆向最大匹配算法,根据自己补充的一个 9 万条词语的自定义词库(与 ICTCLAS 词库中的词语不重复),对 ICTCLAS 分词结果进行合并处理,输出最终分词结果。由于 ICTCLAS 3.0 共享版只支持 GBK 编码,因此,如果是 UTF-8 编码的字符串,可以先用 PHP 的 iconv 函数转换成 GBK 编码,再用 phpcws_split 函数进行分词处理,最后转换回 UTF-8 编码。

性能:5 8字节的一句话 ——“2009 年 2 月 13 日,我编写了一款PHP 中文分词扩展: PHPCWS 1.0.0。 ” ,分词速度只需 0.0003 秒。对于那些采用二元交叉切分的搜索引擎, PHPCWS 用在前端搜索层对用户输入的搜索关键字、短语进行分词处理,同样适合。 PHPCWS 开发的目的正在于此,对于短句、小文本中文分词切分,速度非常之快。

libmmseg

语言和平台: 用C++ 编写的开源的中文分词软件, libmmseg 主要被作者用来实现 Sphinx 全文检索软件的中文分词功能,因此作者给 Sphinx 提供了一个补丁文件,可以让 Sphinx 集成 libmmseg ,从而支持对于中文文章的全文检索功能。 libmmseg 从 0.7.2版本开始,作者提供了 ruby 调用的接口,所以我们可以直接在ruby 程序里面调用 libmmseg 进行分词了。特别是我们可以用 ferret 去调用 libmmseg 分词功能,从而让 ruby 原生支持中文的全文检索。

算法 :“基于词库的最大匹配算法 ”

性能:分词速度为每秒300KB左右。

OpenCLAS

是一个开源的中文词法分析库。

主要功能:其中包括了中文分词、词性标注等功能。系统使用基于概率的多层HMM 。可以对已登录词和未登录词进行识别分析。OpenCLAS是对原有的 ICTCLAS ( 中科院中文词法分析系统 ) 进行的重写。 OpenCLAS 将不包含任何 ICTCLAS 中的源代码,并且以 BSD 协议发布。因此其代码可以在满足 BSD 协议的前提下,用于包括商用在内的各种场合。OpenCLAS将包含三个语言分支,C++, Java 和 C# 。 ( 目前只实现了 C++ 的版本 ) 。

CRF++(上海交大)

项目网址:http://code.google.com/p/crfpp/

详细介绍:http://crfpp.googlecode.com/svn/trunk/doc/index.html

个人主页:http://bcmi.sjtu.edu.cn/~zhaohai/index.ch.html

参考原文地址:
http://ling0322.info/2013/02/13/cws-intro.html http://www.onexin.net/to-achieve-the-18-chinese-word-segmentation-tool/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: