词形还原工具对比
2016-01-21注: 本文仅讨论英文
词形还原(Lemmatization)
在英文当中,一些词会在不同的情况中有不同的形态:名词有单复数,动词有时态和语态,形容词有比较级。而在自然语言处理的一些场景中,这种形态的差异是没有意义的甚至有干扰作用,需要将不同形态的词转换为其 原型 ,这种处理就称为 "词形还原(Lemmatization/Lemmatisation)" ,得到的原型被称为 "词元(Lemma)" 。
举栗子:
- dogs -> dog, cats -> cat
- doing -> do, done -> do
- better -> good
为什么说词的不同形态有干扰作用呢?这么说其实不太严谨,要结合实际应用来说才是有意义的,不妨以文档相似计算这个应用来看一看。
假设我们有三个文档,内容分别为:
D1: I work at home D2: I was working at home D3: I was sleeping at home
从表达的内容上来看,我们会认为 D1 和 D2 是更接近的,而 D2 和 D3 表达的是两件事情。接下来计算一下 Document-Term 矩阵
D1 | D2 | D3 | |
---|---|---|---|
I | 1 | 1 | 1 |
was | 0 | 1 | 1 |
work | 1 | 0 | 0 |
working | 0 | 1 | 0 |
sleeping | 0 | 0 | 1 |
at | 1 | 1 | 1 |
home | 1 | 1 | 1 |
然后计算三个文档之间两两的相似性,为计算简单,这里定义文档相似性为: 两个文档在表中对应的列中 相同位的个数 ,那么
D1 | D2 | D3 | |
---|---|---|---|
D1 | 7 | 4 | 4 |
D2 | 4 | 7 | 5 |
D3 | 4 | 5 | 7 |
结果是: D2 和 D3 最相似 —— 这和预期的结果是不一致的。
如果对文档中每个词都进行词形还原,那么结果会不一样。
注意,词形还原(lemmatization)与词干提取(stemming)在一些词的表现上很相似,但它们是两个东西。
词形还原的工具
Python: NLTK
NLTK 是著名的 Python 自然语言处理包,其中包含了非常多的自然语言处理相关方法和工具,其中也包含了词形还原的功能。
NLTK 中的词形还原功能依赖 WordNet 语料和一个名为 averaged_perceptron_tagger 的词性标注集,所以在使用其词形还原方法前需要先下载相关的数据:
import nltk nltk.download("wordnet") nltk.download("averaged_perceptron_tagger")
使用方法:
from nltk.stem import WordNetLemmatizer lemmatizer = WordNetLemmatizer() print lemmatizer.lemmatize('dogs') print lemmatizer.lemmatize('working', pos='v')
NLTK 里这个词形还原工具的一个问题是需要手动指定词性,比如上面例子中的 "working" 这个词,如果不加后面那个 pos 参数,输出的结果将会是 "working" 本身。
如果希望在实际应用中使用 NLTK 进行词形还原,一个完整的解决方案是:
- 输入一个完整的句子
- 用 NLTK 提供的工具对句子进行分词和词性标注
- 将得到的词性标注结果转换为 WordNet 的格式
- 使用 WordNetLemmatizer 对词进行词形还原
其中分词和词性标注又有数据依赖:
nltk.download("punkt") nltk.download("maxent_treebank_pos_tagger")
给一个小 demo
from nltk.corpus import wordnet from nltk import word_tokenize, pos_tag from nltk.stem import WordNetLemmatizer def get_wordnet_pos(treebank_tag): if treebank_tag.startswith('J'): return wordnet.ADJ elif treebank_tag.startswith('V'): return wordnet.VERB elif treebank_tag.startswith('N'): return wordnet.NOUN elif treebank_tag.startswith('R'): return wordnet.ADV else: return None def lemmatize_sentence(sentence): res = [] lemmatizer = WordNetLemmatizer() for word, pos in pos_tag(word_tokenize(sentence)): wordnet_pos = get_wordnet_pos(pos) or wordnet.NOUN res.append(lemmatizer.lemmatize(word, pos=wordnet_pos)) return res
Python: Pattern
Pattern 是一个 Python 的数据挖掘库,还实现了自然语言处理、机器学习以及数据可视化等一整套的功能,是一个非常强大的库, Github 上 4000 多个 star 呢。
Pattern 中的 en 模块是专门用于英文的自然语言处理的,实现了很多非常棒的方法,比如:
from pattern.en import quantify print quantify(['goose', 'goose', 'duck', 'chicken', 'chicken', 'chicken']) print quantify({'carrot': 100, 'parrot': 20}) print quantify('carrot', amount=1000)
再比如:
from pattern.en import comparative, superlative print comparative('bad') print superlative('bad')
嗯,跑题了……使用 Pattern 进行词形还原在形式上非常简单,如下所示:
from pattern.en import lemma print lemma('working')
So easy!完全不用管什么词性标注之类的。
Python: TextBlob
TextBlob 是一个专注自然语言处理的 Python 库,集成了 NLTK 和 Pattern 的一些功能。其中的词形还原功能使用如下:
from textblob import TextBlob blob = TextBlob('I was working at home') print blob.words for word in blob.words: print word.lemmatize()
结果并不是很理想,同 NLTK 一样,可以传入词性来使词形提高还原结果。
Tree Tagger
Tree Tagger 是一个命令行词性标注工具,词形还原是它附带的功能。
安装:
- 下载词性标注器: Linux / Mac OS-X
- 下载词性标注 脚本
- 下载安装工具: install-tagger.sh
- 下载需要处理的语言的参数文件: 英语
将上述下载好的资源放到同一个目录中,其中的压缩包不需要解压,直接执行 install-tagger.sh
chmod +x install-tagger.sh && ./install-tagger.sh
完成上述操作后将会在当前目录中生成 bin 和 cmd 两个目录,其中是一些可执行程序或脚本,不多介绍。想要进行词形还原,以英语为例,可以这么做:
echo 'I was working at home' | tree-tagger-english