将动词/名词/形容词的词形相互转换

36

我希望有一个Python库函数能够在不同的词性之间进行翻译/转换。有时它应该输出多个单词(例如,“coder”和“code”都是动词“to code”的名词形式,其中一个是主语,另一个是宾语)

# :: String => List of String
print verbify('writer') # => ['write']
print nounize('written') # => ['writer']
print adjectivate('write') # => ['written']

我主要关心动词与名词的相互转换,因为我想写一个笔记程序。例如,我可以写"咖啡因拮抗A1"或"咖啡因是A1拮抗剂",通过一些自然语言处理技术,它可以理解它们意思相同(我知道这不容易,并且需要进行解析而不仅仅是标注的自然语言处理,但我想制作一个原型)。

类似的问题... 将形容词和副词转换为它们的名词形式 (此答案只涉及到基本词性还原,我想要进行更深入的词性转换)

附:在语言学中被称为“词类转换”,详情请见http://en.wikipedia.org/wiki/Conversion_%28linguistics%29


1
我不知道它是否能够做到这一点,但是看一下NLTK。http://nltk.org/ - Lennart Regebro
你将如何处理歧义的情况?例如,“diguise”根据上下文可以是动词或名词。 - Joel Cornett
1
nounize('disguise') == ['disguise']verbify('disguise') == ['disguise']adjectivate('disguise') == ['disguised'] 都是正确的。 - sam boosalis
nounize视为从任何词性到某些名词的模糊转换。它不知道您想要"coder"还是"code",但它提供了完整的超集,稍后NLP可以消除歧义。 - sam boosalis
你的标签中有NLTK,所以你是否在寻找其他可以实现这个功能的库? NLTK是否无法胜任此任务,或者您正在寻找可以完成此任务的NLTK库? - Maus
首选NLTK,但任何Python都可以。 - sam boosalis
5个回答

24

这更像是一种启发式的方法。我只是编写了它,所以对于样式表示歉意。它使用了WordNet中的derivationally_related_forms()函数。我已经实现了名词化。我猜动词化也应该类似。根据我的测试结果来看,效果还不错:

from nltk.corpus import wordnet as wn

def nounify(verb_word):
    """ Transform a verb to the closest noun: die -> death """
    verb_synsets = wn.synsets(verb_word, pos="v")

    # Word not found
    if not verb_synsets:
        return []

    # Get all verb lemmas of the word
    verb_lemmas = [l for s in verb_synsets \
                   for l in s.lemmas if s.name.split('.')[1] == 'v']

    # Get related forms
    derivationally_related_forms = [(l, l.derivationally_related_forms()) \
                                    for l in    verb_lemmas]

    # filter only the nouns
    related_noun_lemmas = [l for drf in derivationally_related_forms \
                           for l in drf[1] if l.synset.name.split('.')[1] == 'n']

    # Extract the words from the lemmas
    words = [l.name for l in related_noun_lemmas]
    len_words = len(words)

    # Build the result in the form of a list containing tuples (word, probability)
    result = [(w, float(words.count(w))/len_words) for w in set(words)]
    result.sort(key=lambda w: -w[1])

    # return all the possibilities sorted by probability
    return result

1
这个答案已过时,请查看下面 @stuart 给出的更新答案。 - William

15

这里有一个理论上能够在名词/动词/形容词/副词之间进行转换的函数,我从here中更新了它(最初由bogs编写,我相信),以便符合nltk 3.2.5的要求,现在synset.lemmassysnset.name是函数。

from nltk.corpus import wordnet as wn

# Just to make it a bit more readable
WN_NOUN = 'n'
WN_VERB = 'v'
WN_ADJECTIVE = 'a'
WN_ADJECTIVE_SATELLITE = 's'
WN_ADVERB = 'r'


def convert(word, from_pos, to_pos):    
    """ Transform words given from/to POS tags """

    synsets = wn.synsets(word, pos=from_pos)

    # Word not found
    if not synsets:
        return []

    # Get all lemmas of the word (consider 'a'and 's' equivalent)
    lemmas = []
    for s in synsets:
        for l in s.lemmas():
            if s.name().split('.')[1] == from_pos or from_pos in (WN_ADJECTIVE, WN_ADJECTIVE_SATELLITE) and s.name().split('.')[1] in (WN_ADJECTIVE, WN_ADJECTIVE_SATELLITE):
                lemmas += [l]

    # Get related forms
    derivationally_related_forms = [(l, l.derivationally_related_forms()) for l in lemmas]

    # filter only the desired pos (consider 'a' and 's' equivalent)
    related_noun_lemmas = []

    for drf in derivationally_related_forms:
        for l in drf[1]:
            if l.synset().name().split('.')[1] == to_pos or to_pos in (WN_ADJECTIVE, WN_ADJECTIVE_SATELLITE) and l.synset().name().split('.')[1] in (WN_ADJECTIVE, WN_ADJECTIVE_SATELLITE):
                related_noun_lemmas += [l]

    # Extract the words from the lemmas
    words = [l.name() for l in related_noun_lemmas]
    len_words = len(words)

    # Build the result in the form of a list containing tuples (word, probability)
    result = [(w, float(words.count(w)) / len_words) for w in set(words)]
    result.sort(key=lambda w:-w[1])

    # return all the possibilities sorted by probability
    return result


convert('direct', 'a', 'r')
convert('direct', 'a', 'n')
convert('quick', 'a', 'r')
convert('quickly', 'r', 'a')
convert('hunger', 'n', 'v')
convert('run', 'v', 'a')
convert('tired', 'a', 'r')
convert('tired', 'a', 'v')
convert('tired', 'a', 'n')
convert('tired', 'a', 's')
convert('wonder', 'v', 'n')
convert('wonder', 'n', 'a')

如下所示,它的效果并不是很好。它无法在形容词和副词之间切换(这是我的具体目标),但在其他情况下它会给出一些有趣的结果。

>>> convert('direct', 'a', 'r')
[]
>>> convert('direct', 'a', 'n')
[('directness', 0.6666666666666666), ('line', 0.3333333333333333)]
>>> convert('quick', 'a', 'r')
[]
>>> convert('quickly', 'r', 'a')
[]
>>> convert('hunger', 'n', 'v')
[('hunger', 0.75), ('thirst', 0.25)]
>>> convert('run', 'v', 'a')
[('persistent', 0.16666666666666666), ('executive', 0.16666666666666666), ('operative', 0.16666666666666666), ('prevalent', 0.16666666666666666), ('meltable', 0.16666666666666666), ('operant', 0.16666666666666666)]
>>> convert('tired', 'a', 'r')
[]
>>> convert('tired', 'a', 'v')
[]
>>> convert('tired', 'a', 'n')
[('triteness', 0.25), ('banality', 0.25), ('tiredness', 0.25), ('commonplace', 0.25)]
>>> convert('tired', 'a', 's')
[]
>>> convert('wonder', 'v', 'n')
[('wonder', 0.3333333333333333), ('wonderer', 0.2222222222222222), ('marveller', 0.1111111111111111), ('marvel', 0.1111111111111111), ('wonderment', 0.1111111111111111), ('question', 0.1111111111111111)]
>>> convert('wonder', 'n', 'a')
[('curious', 0.4), ('wondrous', 0.2), ('marvelous', 0.2), ('marvellous', 0.2)]

希望这能为某人节省一些麻烦


非常棒的答案。关于在其他语言中完成相同任务的任何提示? derivationally_related_forms() 在意大利语中似乎不起作用:我没有收到任何错误,但它始终返回空列表。 - sato

4

我知道这并不能完全回答你的问题,但它确实回答了其中很大一部分。我建议查看以下链接: http://nodebox.net/code/index.php/Linguistics#verb_conjugation 这个Python库可以对动词进行变形,并识别单词是动词、名词还是形容词。

示例代码:

print en.verb.present("gave")
print en.verb.present("gave", person=3, negate=False)
>>> give
>>> gives

它还可以对单词进行分类。
print en.is_noun("banana")
>>> True

下载链接在顶部。

是的,我在这里看到了,但它只能在同一词性内进行转换(而不是跨越不同词性)。https://dev59.com/GW865IYBdhLWcg3wkPaD?rq=1 - sam boosalis

3

一种方法是使用一个带有词性标记和单词形态映射的词典。如果您获取或创建这样的词典(如果您可以访问任何传统词典的数据,因为所有词典都列出单词的词性标记以及所有派生形式的基本形式,这是完全可能的),您可以使用以下代码:

def is_verb(word):
    if word:
        tags = pos_tags(word)
        return 'VB' in tags or 'VBP' in tags or 'VBZ' in tags \
               or 'VBD' in tags or 'VBN' in tags:

def verbify(word):
    if is_verb(word):
        return word
    else:
       forms = []
       for tag in pos_tags(word):
           base = word_form(word, tag[:2])
           if is_verb(base):
              forms.append(base)
       return forms

0

由于现在的语言模型已经相当成熟,一个好主意可能是找到与向量空间距离最小的动词/名词/形容词。


1
inriazk,这可能更适合作为原帖的评论,而不是对问题的建议答案。 - Todd Walton

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