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

46

我尝试了所有的nltk词干提取方法,但对于某些单词它给出了奇怪的结果。

例如:

它经常在不应该的情况下切掉单词的结尾:

  • poodle => poodl
  • article => articl

或者不能很好地进行词干提取:

  • easily和easy没有被提取为相同的单词
  • leaves、grows、fairly没有被提取

你知道Python中其他的词干提取库或好的词典吗?

谢谢


2
这些结果并不奇怪,因为“词干提取”是将屈折(或有时派生)单词缩减为其词干、基本或根形式的过程——通常是书面单词形式。更多详情请查看此处 - eliasah
顺便提一下,NLTK 是构建 Python 程序处理人类语言数据的最佳平台。 - eliasah
你可能只需要针对英语的词干提取器,对吗? - dzieciou
7个回答

183
你获得的结果(一般来说)是英文分词器的期望输出。你说你尝试了“所有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'

23
应选择此答案。 - o-90
7
词形还原器和词干提取器之间的区别是什么?词形还原器尝试将单词还原为其基本形式,即它们在字典中的词元形式。相比之下,词干提取器则通过删除单词的后缀来得到一个较小的单词核心。例如,对于单词“running”,词形还原器会将其还原为“run”,而词干提取器会将其提取为“run”。 - Vipul Jain
5
需要翻译的内容:One thing to add: The lemmatizer produces better results when paired with a POS tagger; the default POS it tries to match for is nouns (try the lemmatizer with the word "ate").需要翻译为:补充一点:使用词形归并器和词性标注器配对使用可以获得更好的效果;它默认尝试匹配名词的词性(可以尝试使用单词 "ate" 来使用词形归并器)。 - Michael
lemmatizer.lemmatize('randomly') # 输出 'randomly',stemmer.stem('randomly') # 输出 'random'。你无法获胜。(nltk词形还原器,来自词干提取器包) - jason
2
对于第一个例子,为什么叫做“stemmer”?它对我不起作用,但是“stem”可以。 - Shayan

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 Stemmer。以下是其Python实现的链接:link。示例代码在此处。
>>> 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']

我在哪里可以获取那些“.dic”和“.aff”文件? - Naveen Reddy Marthala
1
@NaveenKumar 我不记得我五年前从哪里使用过,但是谷歌搜索会导向这个链接 https://github.com/ropensci/hunspell/tree/master/inst/dict - 0xF

7

词干处理器的侵略性因人而异。对于英语,Porter是最具攻击性的词干处理器之一。我发现它通常会带来更多的负面影响而非帮助。

在轻松的一面,您可以使用建议过的词形还原器或轻量级算法词干处理器。

词形还原器的限制在于无法处理未知单词。

个人喜欢 Krovetz 词干处理器,它是一个混合解决方案,结合了字典词形还原器和轻量级词干处理器以处理词汇表外的单词。Krovetz 还在 Elasticsearch 中提供 kstem 或 light_stemmer 选项。pypi 上有一个 Python 实现,链接为 https://pypi.org/project/KrovetzStemmer/,不过那不是我用过的。

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

以下是一些比较各种词干处理算法的论文:


5

词干提取是指去除后缀(通常仅限于后缀,据我所试,nltk的词干提取器无法去除前缀,更不用说中缀了)。 因此,我们可以明确地将词干提取称为一个愚蠢/不太智能的程序。它在进行词干提取之前不会检查单词是否具有含义。 例如,如果您尝试对“xqaing”进行词干提取,虽然这不是一个单词,但它将去除“-ing”并给出“xqa”。

因此,为了使用更智能的系统,可以使用词形还原器。 词形还原器使用以WordNet和字典形式呈现的良好形式的词元(单词)。 因此,它始终返回并接受正确的单词。但是,由于需要遍历所有单词以找到相关单词,因此速度较慢。


0

这个问题已经有非常好的答案了,但我想补充一些我认为可能有用的信息。在我的研究中,我发现了一个链接,它提供了关于词干提取和词形还原的详细信息https://nlp.stanford.edu/IR-book/html/htmledition/stemming-and-lemmatization-1.html

以下是该页面的一些见解:

词干提取和词形还原

由于语法原因,文档将使用单词的不同形式,例如 organize、organizes 和 organizing。此外,还有一些具有相似含义的派生词族,例如 democracy、democratic 和 democratization。在许多情况下,搜索其中一个单词并返回包含该集合中另一个单词的文档似乎很有用。

词干提取和词形还原的目标是将单词的屈折形式和有时具有派生关系的形式减少到一个共同的基本形式。例如:

am、are、is -> be car、cars、car's、cars' -> car 这种文本映射的结果将会是: the boy's cars are different colors -> the boy car be differ color 此外,nltk包已经更新,您可以使用“from nltk.stem import WordNetLemmatizer”导入WordNetLemmatizer。词形还原器需要在使用之前下载一个软件包,下面的命令适用于3.6.1版本。
import nltk

nltk.download("wordnet")

-1
在我的聊天机器人项目中,我使用了PorterStemmer。然而,LancasterStemmer也可以达到同样的目的。最终的目标是将单词还原为其根形式,以便我们可以搜索并与搜索词输入进行比较。
例如: from nltk.stem import PorterStemmer ps = PorterStemmer()
def SrchpattrnStmmed(self):
    KeyWords =[]
    SrchpattrnTkn = word_tokenize(self.input)
    for token in SrchpattrnTkn:
        if token not in stop_words:
            KeyWords.append(ps.stem(token))
            continue
    #print(KeyWords)
    return KeyWords

希望这能有所帮助。


-8

Python实现的Porter、Porter2、Paice-Husk和Lovins英文词干提取算法可在词干提取包中获取。


看起来他们使用了不同的算法。我会尝试一下,谢谢! - PeYoTlL
2
请注意,词干提取是纯Python实现的,速度不如PyStemmer快,后者是一个包装在C库中的包,也可以在PyPi中使用。 - Spaceghost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接