nlp - 词性标注后对单词进行词形还原会产生意想不到的结果

标签 nlp nltk pos-tagger lemmatization python-3.5

我正在使用带有 nltk pos_tag 函数和 WordNetLemmatizer 的 python3.5。我的目标是扁平化数据库中的单词以对文本进行分类。我正在尝试使用词形还原器进行测试,并且在对相同标记使用 POS 标记器时遇到奇怪的行为。在下面的示例中,我有一个包含三个字符串的列表,当在 POS 标记器中运行它们时,每个其他元素都作为名词 (NN) 返回,其余元素作为动词 (VBG) 返回。

这会影响词形还原。输出看起来像这样:

pos Of token: v
lemmatized token: skydive
pos Of token: n
lemmatized token: skydiving
pos Of token: v
lemmatized token: skydive

如果我向相同字符串列表中添加更多元素,则相同的模式将继续。我正在使用的完整代码是这样的:

tokens = ['skydiving', 'skydiving', 'skydiving']
lmtzr=WordNetLemmatizer()

def get_wordnet_pos(treebank_tag):
    if treebank_tag.startswith('J'):
        return 'a'
    elif treebank_tag.startswith('V'):
        return 'v'
    elif treebank_tag.startswith('N'):
        return 'n'
    elif treebank_tag.startswith('R'):
        return 'r'
    elif treebank_tag.startswith('S'):
        return ''
    else:
        return ''

numTokens = (len(tokens))
for i in range(0,numTokens):
    tokens[i]=tokens[i].replace(" ","")

noSpaceTokens = pos_tag(tokens)

for token in noSpaceTokens:
    tokenStr = str(token[1])
    noWhiteSpace = token[0].replace(" ", "")
    preLemmed = get_wordnet_pos(tokenStr)
    print("pos Of token: " + preLemmed)
    lemmed = lmtzr.lemmatize(noWhiteSpace,preLemmed)
    print("lemmatized token: " + lemmed)

最佳答案

简而言之:

当进行词性标注时,您需要一个上下文句子,而不是不合语法的标记列表。

当对脱离上下文的句子进行词形还原时,获得正确词形的唯一方法是手动指定 pos 标签。


长:

词性标注器通常适用于整个句子,而不是单个单词。当您尝试脱离上下文标记单个单词时,您得到的是最常见的标记。

要验证在标记单个单词(即只有 1 个单词的句子)时,它始终给出相同的标记:

>>> from nltk.stem import WordNetLemmatizer
>>> from nltk import pos_tag
>>> ptb2wn_pos = {'J':'a', 'V':'v', 'N':'n', 'R':'r'}
>>> sent = ['skydive']
>>> most_frequent_tag = pos_tag(sent)[0][1]
>>> most_frequent_tag
'JJ'
>>> most_frequent_tag = ptb2wn_pos[most_frequent_tag[0]]
>>> most_frequent_tag
'a'
>>> for _ in range(1000): assert ptb2wn_pos[pos_tag(sent)[0][1][0]] == most_frequent_tag;
... 
>>>

现在,如果句子只有 1 个单词,默认情况下标记始终为“a”,因此 WordNetLemmatizer 将始终返回 skydive:

>>> wnl = WordNetLemmatizer()
>>> wnl.lemmatize(sent[0], pos=most_frequent_tag)
'skydive'

让我们看看句子上下文中单词的引理:

>>> sent2 = 'They skydrive from the tower yesterday'
>>> pos_tag(sent2.split())
[('They', 'PRP'), ('skydrive', 'VBP'), ('from', 'IN'), ('the', 'DT'), ('tower', 'NN'), ('yesterday', 'NN')]
>>> pos_tag(sent2.split())[1]
('skydrive', 'VBP')
>>> pos_tag(sent2.split())[1][1]
'VBP'
>>> ptb2wn_pos[pos_tag(sent2.split())[1][1][0]]
'v'

因此,当您执行 pos_tag 时,标记输入列表的上下文很重要。

在您的示例中,您有一个列表['skydiving', 'skydiving', 'skydiving'],这意味着您要加后置标签的句子是一个不语法的句子:

skydiving skydiving skydiving

并且 pos_tag 函数认为这是一个正常的句子,因此给出标签:

>>> sent3 = 'skydiving skydiving skydiving'.split()
>>> pos_tag(sent3)
[('skydiving', 'VBG'), ('skydiving', 'NN'), ('skydiving', 'VBG')]

在这种情况下,第一个是动词,第二个单词是名词,第三个单词是动词,这将返回以下引理(您不希望出现):

>>> wnl.lemmatize('skydiving', 'v')
'skydive'
>>> wnl.lemmatize('skydiving', 'n')
'skydiving'
>>> wnl.lemmatize('skydiving', 'v')
'skydive'

因此,如果我们的标记列表中有一个有效的语法句子,则输出可能看起来非常不同

>>> sent3 = 'The skydiving sport is an exercise that promotes diving from the sky , ergo when you are skydiving , you feel like you are descending to earth .'
>>> pos_tag(sent3.split())
[('The', 'DT'), ('skydiving', 'NN'), ('sport', 'NN'), ('is', 'VBZ'), ('an', 'DT'), ('exercise', 'NN'), ('that', 'IN'), ('promotes', 'NNS'), ('diving', 'VBG'), ('from', 'IN'), ('the', 'DT'), ('sky', 'NN'), (',', ','), ('ergo', 'RB'), ('when', 'WRB'), ('you', 'PRP'), ('are', 'VBP'), ('skydiving', 'VBG'), (',', ','), ('you', 'PRP'), ('feel', 'VBP'), ('like', 'IN'), ('you', 'PRP'), ('are', 'VBP'), ('descending', 'VBG'), ('to', 'TO'), ('earth', 'JJ'), ('.', '.')]

关于nlp - 词性标注后对单词进行词形还原会产生意想不到的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33157847/

相关文章:

python - nltk:如何搜索某些单词之间的联系?

python - 使用 NLTK 对德语文本进行 Pos 标记

python - 在 python 中创建代码以从列表中获取最常见的标签和值对

python - 亚洲语言情感分析的代码示例 - Python NLTK

c++ - 我如何在 C++ 中使用 python 库?

python - Gensim Doc2Vec most_similar() 方法没有按预期工作

python - 使用 Python 从基于 Topic 的文本中提取关键短语

python - 为什么使用one_hot编码时需要pad_sequences?

python - 具有适用于 Word2Vec 模型的 Keras 功能 API 的产品合并层