在 NLTK 中使用 Stanford NLP 工具包

src: http://www.zmonster.me/2016/06/08/use-stanford-nlp-package-in-nltk.html#orgheadline1

ZMonster's Blog 巧者劳而智者忧,无能者无所求,饱食而遨游,泛若不系之舟

在 NLTK 中使用 Stanford NLP 工具包
08 Jun 2016目录
NLTK 与 Stanford NLP
安装和配置注意事项
StanfordSegmenter
StanfordTokenizer
StanfordNERTagger 和 StanfordPOSTagger
StanfordParser, StanfordDependencyParser
StanfordNeuralDependencyParser

基本使用使用 StanfordSegmenter 和 StanfordTokenizer 进行分词
使用 StanfordNERTagger 进行命名实体识别
使用 StanfordPOSTagger 进行词性标注
使用 StanfordParser 进行句法分析
使用 StanfordDependencyParser 进行依存句法分析

NLTK 与 Stanford NLP
NLTK 是一款著名的 Python 自然语言处理(Natural Language Processing, NLP)工具包,在其收集的大量公开数据集、模型上提供了全面、易用的接口,涵盖了分词、词性标注(Part-Of-Speech tag, POS-tag)、命名实体识别(Named Entity Recognition, NER)、句法分析(Syntactic Parse)等各项 NLP 领域的功能。
Stanford NLP 是由斯坦福大学的 NLP 小组开源的 Java 实现的 NLP 工具包,同样对 NLP 领域的各个问题提供了解决办法。
斯坦福大学的 NLP 小组是世界知名的研究小组,如果能将 NLTK 和 Stanford NLP 这两个工具包结合起来使用,那自然是极好的!在 2004 年 Steve Bird 在 NLTK 中加上了对 Stanford NLP 工具包的支持,通过调用外部的 jar 文件来使用 Stanford NLP 工具包的功能。
从 NLTK 的 commit 历史中可以找到相应的提交记录:

commit e1372fef56bfb88d02fdb6c0ea88474d5f414a38
Author: Steven Bird <stevenbird1@gmail.com>
Date: Tue Aug 3 12:20:20 2004 +0000 
    added Stanford svn/trunk@2088

现在的 NLTK 中,通过封装提供了 Stanford NLP 中的以下几个功能:
分词
词性标注
命名实体识别
句法分析,依存句法分析

安装和配置
NLTK 3.2 之后加入了用于中文分词的 StanfordSegmenter 这个类,作者是知名 NLP 博主 52nlp,见 相关文章。而 NLTK 3.1 及之前则只有以下几个类:
分词: StanfordTokenizer
词性标注: StanfordPOSTagger
命名实体识别: StanfordNERTagger
句法分析: StanfordParser
依存句法分析: StanfordDependencyParser, StanfordNeuralDependencyParser

方便起见,本文以 NLTK 3.2 这个版本来说明如何进行相关的安装和配置,3.1 及之前的版本基本相同。

注意事项
需要注意这么几点:
Stanford NLP 工具包自 2014 年 10 月后(大概是 version 3.5.0)需要 Java 8 及之后的版本,如果出错请检查 Java 版本
下面的配置过程都以 Stanford NLP 3.6.0 为例,如果使用的是其他版本,请注意替换相应的文件名
下面的配置过程以 NLTK 3.2 为例,如果使用 NLTK 3.1,需要注意该旧版本中 StanfordSegmenter 未实现,其余大致相同
下面的配置过程是针对不同的接口分别讲述各自如何配置,根据来自 NLTK 的源代码,分别是

nltk/tokenize/stanford.py
nltk/tag/stanford.py
nltk/parse/stanford.py

如果不想了解这些细节,可以参考 NLTK 官方 wiki 页面上的内容,但需要注意的是,StanfordSegmenter 和 StanfordNeuralDependencyParser 这两者的配置和其他的都不一样,而 wiki 页面上并未覆盖到这部分内容。

事实上,也可以完全不进行环境变量设置,但这就需要在每次调用的时候手动指定参数

StanfordSegmenter
http://nlp.stanford.edu/software/segmenter.html 处下载 stanford-segmenter-2015-12-09.zip (version 3.6.0)
将 stanford-segmenter-2015-12-09.zip 解压, 并将解压目录中的 stanford-segmenter-3.6.0.jar 拷贝为 stanford-segmenter.jar
stanford-segmenter.jarslf4j-api.jar 加入到 CLASSPATH 中去
例:

export STANFORD_SEGMENTER_PATH="$HOME/stanford/segmenter"export CLASSPATH="$CLASSPATH:$STANFORD_SEGMENTER_PATH/stanford-segmenter.jar:$STANFORD_SEGMENTER_PATH/slf4j-api.jar"

之所以要将 stanford-segmenter.jarslf4j-api.jar 加入到 CLASSPATH 中,是因为在 StanfordSegmenter 的实现中显式依赖了这两个文件,并且优先在 CLASSPATH 中寻找这两个文件。如果在 CLASSPATH 中找不到 stanford-segmenter.jar ,则会在环境变量 STANFORD_SEGMENTER 指定的路径中寻找;同样的,如果找不到 slf4j-api.jar ,则会在环境变量 SLF4J 指定的路径中寻找。其他几个类也有同样的依赖设置,为了统一管理,可以将所有依赖的 jar 文件都加入到 CLASSPATH 中去,当然分别为不同的 jar 文件设置不同的环境变量也是可以的。
除了设置环境变量,也可以通过函数参数来传入依赖的 jar 文件的准确路径,此时将会忽略环境变量设置。

StanfordTokenizer
http://nlp.stanford.edu/software/tagger.html 中下载 stanford-postagger-full-2015-12-09.zip (version 3.6.0)
stanford-postagger-full-2015-12-09.zip 解压
将解压目录中的 stanford-postagger.jar 加入到 CLASSPATH 中,或者设置到环境变量

STANFORD_POSTAGGER 中
export STANFORD_POSTAGGER_PATH="$HOME/stanford/postagger"export CLASSPATH="$CLASSPATH:$STANFORD_POSTAGGER_PATH/stanford-postagger.jar"

export STANFORD_POSTAGGER="$HOME/stanford/postagger/stanford-postagger.jar"

StanfordNERTagger 和 StanfordPOSTagger
在 NLTK 里,StanfordNERTagger 和 StanfordPOSTagger 都继承自 StanfordTagger ,在设置上有共同之处,因此放到一起来讲一下。
http://nlp.stanford.edu/software/CRF-NER.html 处下载 stanford-ner-2015-12-09.zip (version 3.6.0)
http://nlp.stanford.edu/software/tagger.html 中下载 stanford-postagger-full-2015-12-09.zip (version 3.6.0)
stanford-ner-2015-12-09.zipstanford-postagger-full-2015-12-09.zip 都解压
将解压后目录中的 stanford-ner.jarstanford-postagger.jar 加入到 CLASSPATH 中去,和 StanfordTokenizer 不一样,这两个类都只从 CLASSPATH 中寻找对应的 jar 文件(所以为了统一我建议都添加到 CLASSPATH 中去)

export STANFORD_NER_PATH="$HOME/stanford/ner"export STANFORD_POSTAGGER_PATH="$HOME/stanford/postagger"export CLASSPATH="$CLASSPATH:$STANFORD_NER_PATH/stanford-ner.jar:$STANFORD_POSTAGGER_PATH/stanford-postagger.jar"

同时将 stanford-ner-2015-12-09.zip 解压后目录中的 classifiers 目录和 stanford-postagger-full-2015-12-09.zip 解压后目录中的 models 目录加入到环境变量 STANFORD_MODELS 中去
export STANFORD_MODELS="$STANFORD_NER_PATH/classifiers:$STANFORD_POSTAGGER_PATH/models"

StanfordParser, StanfordDependencyParser
StanfordParser 和 StanfordDependencyParser 都继承自 GenericStanfordParser ,使用 stanford-parser.jar 来提供句法分析功能。
http://nlp.stanford.edu/software/lex-parser.html 处下载 stanford-parser-full-2015-12-09.zip (version 3.6.0)
将下载的压缩包解压,并将其中的 stanford-parser.jarstanford-parser-3.6.0-models.jar(这个在不同版本中名称会不一样) 都加入到 CLASSPATH 中

export STANFORD_PARSER_PATH="$HOME/stanford/parser"export CLASSPATH="$CLASSPATH:$STANFORD_PARSER_PATH/stanford-parser.jar:$STANFORD_PARSER_PATH/stanford-parser-3.6.0-models.jar"

或者将 stanford-parser.jar 加入到环境变量 STANFORD_PARSER 中,将 stanford-parser-3.6.0-models.jar 加入到环境变量 STANFORD_MODELS 中

export STANFORD_PARSER="$STANFORD_PARSER_PATH/stanford-parser.jar"export STANFORD_MODELS="$STANFORD_MODELS:$STANFORD_PARSER_PATH/stanford-parser-3.6.0.models.jar"

StanfordNeuralDependencyParser
StanfordNeuralDependencyParser 虽然也继承自 GenericStanfordParser,并且用来进行句法分析,但它使用的 Stanford CoreNLP 中的功能和模型,不依赖 Stanford Parser 这个(子)工具包。
http://stanfordnlp.github.io/CoreNLP/ 处下载 stanford-corenlp-full-2015-12-09.zip
将下载的压缩包解压,并将其中的 stanford-corenlp-3.6.0.jarstanford-corenlp-3.6.0-models.jar 加入到 CLASSPATH 中去

export STANFORD_CORENLP_PATH="$HOME/stanford-corenlp-full-2015-12-09"export CLASSPATH="$CLASSPATH:$STANFORD_CORENLP_PATH/stanford-corenlp-3.6.0.jar:$STANFORD_CORENLP_PATH/stanford-corenlp-3.6.0-models.jar"

或者可以更简单地将解压目录设置为环境变量 STANFORD_CORENLP 的值

export STANFORD_CORENLP=$STANFORD_CORENLP_PATH

基本使用

使用 StanfordSegmenter 和 StanfordTokenizer 进行分词
StanfordSegmenter 是 52nlp 实现的对 Stanford Segmenter 的封装,用来进行中文分词。

# coding: utf-8
from nltk.tokenize import StanfordSegmenter
segmenter = StanfordSegmenter( 
  path_to_sihan_corpora_dict="/home/linusp/stanford/segmenter/data/",   path_to_model="/home/linusp/stanford/segmenter/data/pku.gz",   path_to_dict="/home/linusp/stanford/segmenter/data/dict-chris6.ser.gz")
res = segmenter.segment(u"北海已成为中国对外开放中升起的一颗明星")
print type(res)
print res.encode('utf-8')
<type 'unicode'>
北海 已 成为 中国 对外开放 中 升起 的 一 颗 明星

StanfordSegmenter 的初始化参数说明:
path_to_jar: 用来定位 stanford-segmenter.jar ,在设置了 CLASSPATH 的情况下,该参数可留空
注: 其他所有 Stanford NLP 接口都有 path_to_jar 这个参数,同样在设置了环境变量的情况下可以留空,后面不再另加说明。

path_to_slf4j: 用来定位 slf4j-api.jar ,在设置了 CLASSPATH 或者 SLF4J 这个环境变量的情况下,该参数可留空
path_to_sihan_corpora_dict: 设定为 stanford-segmenter-2015-12-09.zip 解压后目录中的 data 目录,话说这个参数名真是让人摸不着头脑
path_to_model: 用来指定用于中文分词的模型,在 stanford-segmenter-2015-12-09 的 data 目录下,有两个可用模型 pkg.gzctb.gz

需要注意的是,使用 StanfordSegmenter 进行中文分词后,其返回结果并不是 list ,而是一个字符串,各个汉语词汇在其中被空格分隔开。
StanfordTokenizer 可以用来进行英文的分词,使用起来比较简单

# coding: utf-8
from nltk.tokenize import StanfordTokenizer
tokenizer = StanfordTokenizer()
sent = "Good muffins cost $3.88\nin New York. Please buy me\ntwo of them.\nThanks."
print tokenizer.tokenize(sent)
[u'Good', u'muffins', u'cost', u'$', u'3.88', u'in', u'New', u'York', u'.', u'Please', u'buy', u'me', u'two', u'of', u'them', u'.', u'Thanks', u'.']

使用 StanfordNERTagger 进行命名实体识别
所谓命名实体识别,是用来识别并标注文本中的人名、地名、组织机构名等单元,这些单元既是 "命名实体"。

# coding: utf-8
from nltk.tag import StanfordNERTagger
eng_tagger = StanfordNERTagger('english.all.3class.distsim.crf.ser.gz')
print eng_tagger.tag('Rami Eid is studying at Stony Brook University in NY'.split())
[(u'Rami', u'PERSON'), (u'Eid', u'PERSON'), (u'is', u'O'), (u'studying', u'O'), (u'at', u'O'), (u'Stony', u'ORGANIZATION'), (u'Brook', u'ORGANIZATION'), (u'University', u'ORGANIZATION'), (u'in', u'O'), (u'NY', u'O')]

StanfordNERTagger 在初始化时需要指定所使用的模型,在 stanford-ner-2015-12-09.zip 解压后的 classifiers 目录中,有几个可用的英语 NER 模型:
/home/linusp/stanford/ner/classifiers/├── english.all.3class.distsim.crf.ser.gz├── english.all.3class.distsim.prop├── english.conll.4class.distsim.crf.ser.gz├── english.conll.4class.distsim.prop├── english.muc.7class.distsim.crf.ser.gz├── english.muc.7class.distsim.prop├── example.serialized.ncc.ncc.ser.gz└── example.serialized.ncc.prop
如果需要进行中文的命名实体识别,则可以在 Stanford Named Entity Recognizer 页面的 Models 一节找到中文模型的下载链接,下载得到 stanford-chinese-corenlp-2015-12-08-models.jar ,解压后将 edu/stanford/nlp/models/ner/ 目录下的 chinese.misc.distsim.crf.ser.gz 和 chinese.misc.distsim.prop 复制到模型目录下(stanford-ner-2015-12-09/classifiers)即可。

coding: utf-8from nltk.tag import StanfordNERTaggerchi_tagger = StanfordNERTagger('chinese.misc.distsim.crf.ser.gz')sent = u'北海 已 成为 中国 对外开放 中 升起 的 一 颗 明星'for word, tag in chi_tagger.tag(sent.split()): print word.encode('utf-8'), tag

北海 GPE已 O成为 O中国 GPE对外开放 O中 O升起 O的 O一 O颗 O明星 O

使用 StanfordPOSTagger 进行词性标注
所谓词性标注,是根据句子中的上下文信息,给句中每个词确定一个最为合适的词性标记,比如动词、名词、人称代词等。
和 StanfordNERTagger 一样,StanfordPOSTagger 需要的输入也是一个已经分好词的句子,下面是一个英文的词性标注实例:
from nltk.tag import StanfordPOSTaggereng_tagger = StanfordPOSTagger('english-bidirectional-distsim.tagger')print eng_tagger.tag('What is the airspeed of an unladen swallow ?'.split())

[(u'What', u'WP'), (u'is', u'VBZ'), (u'the', u'DT'), (u'airspeed', u'NN'), (u'of', u'IN'), (u'an', u'DT'), (u'unladen', u'JJ'), (u'swallow', u'VB'), (u'?', u'.')]
如果之前配置时下载的是 stanford-postagger-full-xxxx-xx-xx.zip ,在解压后,其中的 models 目录是包含有两个中文模型的,分别是 chinese-distsim.taggerchinese-nodistsim.tagger ,可以直接使用。

coding: utf-8from nltk.tag import StanfordPOSTaggerchi_tagger = StanfordPOSTagger('chinese-distsim.tagger')sent = u'北海 已 成为 中国 对外开放 中 升起 的 一 颗 明星'for _, word_and_tag in chi_tagger.tag(sent.split()): word, tag = word_and_tag.split('#') print word.encode('utf-8'), tag

北海 NR已 AD成为 VV中国 NR对外开放 NN中 LC升起 VV的 DEC一 CD颗 M明星 NN
这个中文的词性标注输出的结果有点奇怪……

使用 StanfordParser 进行句法分析
句法分析在分析单个词的词性的基础上,尝试分析词与词之间的关系,并用这种关系来表示句子的结构。实际上,句法结构可以分为两种,一种是短语结构,另一种是依存结构。前者按句子顺序来提取句法结构,后者则按词与词之间的句法关系来提取句子结构。这里说的句法分析得到的是短语结构。
from nltk.parse.stanford import StanfordParsereng_parser = StanfordParser(model_path=u'edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz')print list(eng_parser.parse("the quick brown fox jumps over the lazy dog".split()))

[Tree('ROOT', [Tree('NP', [Tree('NP', [Tree('DT', ['the']), Tree('JJ', ['quick']), Tree('JJ', ['brown']), Tree('NN', ['fox'])]), Tree('NP', [Tree('NP', [Tree('NNS', ['jumps'])]), Tree('PP', [Tree('IN', ['over']), Tree('NP', [Tree('DT', ['the']), Tree('JJ', ['lazy']), Tree('NN', ['dog'])])])])])])]
得到的结果是一个 list, 其中的元素是 Tree 类型的,在上面这个例子中,这个 list 的长度是 1 ,调用 Tree 的 draw 方法可以将句法树绘制出来。


eng_parse_tree.png

要进行中文的句法分析,只要指定好中文的模型就好,可用的中文模型有两个,分别是 'edu/stanford/nlp/models/lexparser/chinesePCFG.ser.gz' 和 'edu/stanford/nlp/models/lexparser/chineseFactored.ser.gz',依然拿 "北海 已 成为 中国 对外开放 中 升起 的 一 颗 明星" 这句话作为例子,得到的句法树如下所示。

chi_parse_tree.png

使用 StanfordDependencyParser 进行依存句法分析
见上一节,依存句法分析得到的是句子的依存结构。
from nltk.parse.stanford import StanfordDependencyParsereng_parser = StanfordDependencyParser(model_path=u'edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz')res = list(eng_parser.parse("the quick brown fox jumps over the lazy dog".split()))for row in res[0].triples(): print row

((u'fox', u'NN'), u'det', (u'the', u'DT'))((u'fox', u'NN'), u'amod', (u'quick', u'JJ'))((u'fox', u'NN'), u'amod', (u'brown', u'JJ'))((u'fox', u'NN'), u'dep', (u'jumps', u'NNS'))((u'jumps', u'NNS'), u'nmod', (u'dog', u'NN'))((u'dog', u'NN'), u'case', (u'over', u'IN'))((u'dog', u'NN'), u'det', (u'the', u'DT'))((u'dog', u'NN'), u'amod', (u'lazy', u'JJ'))
绘制出来的依存句法结构如下图所示。


dep_parse_tree.png

中文的依存句法分析同理,在初始化时使用中文模型即可,不再赘述。
StanfordNeuralDependencyParser 的使用与 StanfordDependencyParser 一样,但是在本人的机器上执行非常耗时,即使是对一些简单句子,所以这里就不略过不讲了。

Naringu is designed by Rizky AriestiyansyahCopyright © 2016

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容