在Python中最佳的词干提取方法是什么?

46 投票
7 回答
87778 浏览
提问于 2025-04-18 12:36

我尝试了所有nltk的方法来进行词干提取,但对某些词的结果很奇怪。

举个例子

它经常在不该剪掉的地方剪掉词尾:

  • poodle(贵宾犬)变成了 poodl
  • article(文章)变成了 articl

或者提取的效果不好:

  • easily(容易地)和 easy(容易)没有被提取成同一个词
  • leaves(叶子)、grows(生长)、fairly(相当)都没有被提取

你知道其他在Python中进行词干提取的库,或者好的词典吗?

谢谢

7 个回答

5

词干提取就是把单词的后缀去掉(通常只去后缀,至于前缀和中缀,试过的 nltk 词干提取工具都没法处理)。所以我们可以说词干提取是个比较简单的程序,它不会检查一个词在去掉后缀前后是否还有意义。比如,如果你试着提取“xqaing”这个词,虽然它不是个真正的词,程序会把“-ing”去掉,结果给你“xqa”。

为了使用更聪明的系统,可以用词形还原器。词形还原器会使用一些规范的词(也就是词根),这些词来自于词网和字典。这样它总是能返回一个正确的单词。不过,它的速度比较慢,因为它需要检查所有的单词才能找到合适的那个。

7

不同的词干提取器在处理单词时的力度不同。Porter 是一种对英语非常激进的词干提取器,我发现它通常带来的负面影响比正面影响还要多。

如果想要轻松一些,可以考虑使用词形还原器,或者选择一种更温和的算法词干提取器。词形还原器的一个限制是它无法处理不认识的单词。

我个人比较喜欢 Krovetz 词干提取器,它是一种混合解决方案,结合了字典词形还原器和一种轻量级的词干提取器,用于处理不在词汇表中的单词。Krovetz 也可以在 Elasticsearch 中使用 kstemlight_stemmer 选项。Python 也有一个实现,可以在 pypi 上找到,链接是 https://pypi.org/project/KrovetzStemmer/,不过我用的不是这个版本。

另一个选择是 spaCy 中的词形还原器。使用 spaCy 处理后,每个词都有一个 lemma_ 属性。(注意下划线,lemmalemma_ 的数字标识符) - https://spacy.io/api/token

这里有一些论文比较了各种词干提取算法:

15

这里讨论的所有词干提取器都是基于算法的,所以它们有时会产生一些意想不到的结果,比如:

In [3]: from nltk.stem.porter import *

In [4]: stemmer = PorterStemmer()

In [5]: stemmer.stem('identified')
Out[5]: u'identifi'

In [6]: stemmer.stem('nonsensical')
Out[6]: u'nonsens'

要正确获取词的根形式,需要使用基于字典的词干提取器,比如 Hunspell 词干提取器。下面是它的 Python 实现,可以在这个 链接 找到。示例代码在这里:

>>> import hunspell
>>> hobj = hunspell.HunSpell('/usr/share/myspell/en_US.dic', '/usr/share/myspell/en_US.aff')
>>> hobj.spell('spookie')
False
>>> hobj.suggest('spookie')
['spookier', 'spookiness', 'spooky', 'spook', 'spoonbill']
>>> hobj.spell('spooky')
True
>>> hobj.analyze('linked')
[' st:link fl:D']
>>> hobj.stem('linked')
['link']
184

你得到的结果(一般来说)是英文词干提取器的正常表现。你说你尝试了“所有的nltk方法”,但当我试你的例子时,似乎并不是这样。

这里有一些使用PorterStemmer的例子:

import nltk
ps = nltk.stemmer.PorterStemmer()
ps.stem('grows')
'grow'
ps.stem('leaves')
'leav'
ps.stem('fairly')
'fairli'

结果是'grow'、'leav'和'fairli',即使这些是你想要的,它们也是原始单词的词干形式。

如果我们换成Snowball词干提取器,我们需要提供语言作为参数。

import nltk
sno = nltk.stem.SnowballStemmer('english')
sno.stem('grows')
'grow'
sno.stem('leaves')
'leav'
sno.stem('fairly')
'fair'

对于'grows'和'leaves'的结果和之前一样,但'fairly'被提取成了'fair'。

所以在这两种情况下(而且nltk中还有不止两种词干提取器),你说没有被提取的单词,实际上都是被提取了的。LancasterStemmer在输入'easily'或'easy'时会返回'easy'。

也许你其实想要的是一个词形还原器?那样的话,它会返回'article'和'poodle',保持不变。

import nltk
lemma = nltk.wordnet.WordNetLemmatizer()
lemma.lemmatize('article')
'article'
lemma.lemmatize('leaves')
'leaf'
-8

有一些用Python写的程序,可以实现Porter、Porter2、Paice-Husk和Lovins这几种英文词干提取算法。这些程序可以在stemming包里找到。

撰写回答