用nltk搜索类似的含义短语

时间:2014-03-17 11:06:43

标签: python search nlp nltk

我有一堆不相关的段落,我需要遍历它们以找到类似的事件,例如,在我寻找object falls的搜索中,我找到一个布尔值{{1包含以下内容的文字:

  • Box从架子上掉下来
  • 灯泡在地上破碎
  • 一块石膏从天花板上掉下来

True代表:

  • 责备归于莎拉
  • 温度突然下降

我可以将 nltk 用于Falsetokenise并获取 Wordnet tag,但我发现它很难找出如何将 nltk 的活动部件放在一起以达到理想的效果。在寻找同义词之前我应该​​synsets吗?我应该写一个chunk吗?从 treebank 标签转换为Wordnet语法标签时是否有最佳做法? nltk book中没有解释这一点,我在nltk cookbook上找不到它。

答案中包含pandas的答案的奖励积分。


[编辑]:

一些开始使用的代码

context-free grammar

2 个答案:

答案 0 :(得分:7)

我这样做的方法如下:

使用 nltk 查找名词,后跟一个或两个动词。为了符合您的确切规格,我会使用 Wordnet : 应该找到的唯一名词(NN,NNP,PRP,NNS)是与“物理”或“物质”语义关系的唯一名词和唯一的动词(VB,VBZ,VBD等...)应该找到与“秋天”存在语义关系的那些。

我提到“一个或两个动词”,因为动词前面可以有一个辅助词。你还可以做的是创建一个依赖树来发现主语 - 动词关系,但在这种情况下似乎没有必要。

您可能还想确保排除位置名称并保留人名(因为您会接受“John已经堕落”但不是“柏林已经堕落”)。这也可以使用 Wordnet 来完成,地点的标记为“noun.location”。

我不确定在哪种情况下您必须转换标签,因此我无法提供正确的答案,在我看来,在这种情况下您可能不需要:您使用POS标签来识别名词和动词,然后检查每个名词和动词是否属于同义词集。

希望这有帮助。

答案 1 :(得分:0)

不完美,但大部分工作都在那里。现在硬编码代词(例如'it')和 closed-class words 并添加多个目标来处理像'破碎'这样的事情。不是一个单行,但不是一个不可能的任务!

from nltk.tag import pos_tag
from nltk.tokenize import word_tokenize
from pandas import Series, DataFrame
import collections
from nltk import wordnet
wn = wordnet.wordnet

def tag(x):
    return pos_tag(word_tokenize(x))

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flatten(el):
                yield sub
        else:
            yield el

def noun_verb_match(phrase, nouns, verbs):
    res = []
    for i in range(len(phrase) -1):
        if (phrase[i][1] in nouns) &\
            (phrase[i + 1][1] in verbs):
            res.append((phrase[i], phrase[i + 1]))
    return res

def hypernym_paths(word, pos):
    res = [x.hypernym_paths() for x in wn.synsets(word, pos)]
    return set(flatten(res))

def bool_syn(double, noun_syn, verb_syn):
    """
    Returns boolean if noun/verb double contains the target Wordnet Synsets.
    Arguments:
    double: ((noun, tag), (verb, tag))
    noun_syn, verb_syn: Wordnet Synset string (i.e., 'travel.v.01')
    """
    noun = double[0][0]
    verb = double[1][0]
    noun_bool = wn.synset(noun_syn) in hypernym_paths(noun, 'n')
    verb_bool = wn.synset(verb_syn) in hypernym_paths(verb, 'v')
    return noun_bool & verb_bool

def bool_loop(l, f):
    """
    Tests all list elements for truthiness and
    returns True if any is True.
    Arguments:
    l: List.
    e: List element.
    f: Function returning boolean.
    """
    if len(l) == 0:
        return False
    else:
        return f(l[0]) | bool_loop(l[1:], f)

def bool_noun_verb(series, nouns, verbs, noun_synset_target, verb_synset_target):
    tagged = series.map(tag)
    nvm = lambda x: noun_verb_match(x, nouns, verbs)
    matches = tagged.apply(nvm)
    bs = lambda x: bool_syn(x, noun_synset_target, verb_synset_target)
    return matches.apply(lambda x: bool_loop(x, bs))

phrases = ['Box fell from shelf',
           'Bulb shattered on the ground',
           'A piece of plaster fell from the ceiling',
           'The blame fell on Sarah',
           'Berlin fell on May',
           'The temperature fell abruptly',
           'It fell on the floor']

nouns = "NN NNP PRP NNS".split()
verbs = "VB VBD VBZ".split()
noun_synset_target = 'artifact.n.01'
verb_synset_target = 'travel.v.01'

df = DataFrame()
df['text'] = Series(phrases)
df['fall'] = bool_noun_verb(df.text, nouns, verbs, noun_synset_target, verb_synset_target)
df