【问题标题】:Extracting food items from sentences从句子中提取食物
【发布时间】:2017-05-11 08:13:31
【问题描述】:

给定一句话:

我吃了花生酱和果冻三明治和一杯咖啡 早餐

我希望能够从中提取以下食物:

花生酱和果冻三明治

咖啡

到目前为止,使用 POS 标记,我已经能够提取单个食品,即

花生、黄油、果冻、三明治、咖啡

但就像我说的,我需要的是花生酱和果冻三明治,而不是单独的物品。

是否有某种方法可以做到这一点,而无需在后端使用语料库或食品数据库?

【问题讨论】:

  • 你为什么要咖啡而不是杯咖啡?似乎这样会更一致..
  • 一杯咖啡也不错。事实上,这是我的最终目标(同时也捕获数量)。但是,现在我被上述问题困住了。
  • 在不知道(或学习)什么组合是“事物”的情况下,很难确定“X 和 Y”是否是单一食物。
  • 这很困难,因为即使是正确的英文句子也可能是模棱两可的:“我喜欢花生酱和果冻三明治。” ...你喜欢花生酱果冻三明治还是你喜欢花生酱三明治和果冻三明治?
  • 不能用 关键字提取 在 python 中使用 RAKE 或在 java 中使用 KEA 来完成。 cs.cmu.edu/afs/cs/project/jair/pub/volume22/erkan04a-html/…

标签: algorithm nlp


【解决方案1】:

您可以在不使用包含食物语料库的训练集的情况下尝试它,但该方法也可以在没有它的情况下使用。

不是做简单的词性标注,而是结合词性标注做依赖解析。 这样就可以找到短语的多个标记之间的关系,并解析具有限制条件的依赖树,例如名词-名词依赖关系,您应该能够找到相关的块。

您可以使用spacy for dep parsing。这是 displace 的输出:

https://demos.explosion.ai/displacy/?text=peanut%20butter%20and%20jelly%20sandwich%20is%20delicious&model=en&cpu=1&cph=1

  • 您可以在此处使用免费提供的数据,或者更好的方法: https://en.wikipedia.org/wiki/Lists_of_foods 作为训练集 创建一组基本的食物项目(爬行树中的超链接)
  • 基于对新数据的依赖解析,您可以保留 丰富基础数据。例如:如果“黄油”存在于您的 语料库,而“花生酱”是一对经常遇到的 代币,然后“花生”和“花生酱”也被添加到 语料库。
  • 语料库可以保存在一个文件中,该文件可以加载到内存中 在处理时,或者像 redis、aerospike 等数据库。
  • 确保您使用规范化,即小包装、特殊 在语料库和 处理数据。这将增加您的覆盖范围和准确性。

【讨论】:

  • 这是一个漂亮的答案!让我访问了@DhruvPathak 的个人资料 :)
【解决方案2】:

首先使用NLTK的分块提取所有名词短语(代码复制自here):

import nltk
import re
import pprint
from nltk import Tree
import pdb


patterns="""
    NP: {<JJ>*<NN*>+}
    {<JJ>*<NN*><CC>*<NN*>+}
    {<NP><CC><NP>}
    {<RB><JJ>*<NN*>+}
    """

NPChunker = nltk.RegexpParser(patterns)

def prepare_text(input):
    sentences = nltk.sent_tokenize(input)
    sentences = [nltk.word_tokenize(sent) for sent in sentences] 
    sentences = [nltk.pos_tag(sent) for sent in sentences]
    sentences = [NPChunker.parse(sent) for sent in sentences]
    return sentences


def parsed_text_to_NP(sentences):
    nps = []
    for sent in sentences:
        tree = NPChunker.parse(sent)
        print(tree)
        for subtree in tree.subtrees():
            if subtree.label() == 'NP':
                t = subtree
                t = ' '.join(word for word, tag in t.leaves())
                nps.append(t)
    return nps


def sent_parse(input):
    sentences = prepare_text(input)
    nps = parsed_text_to_NP(sentences)
    return nps



if __name__ == '__main__':
    print(sent_parse('I ate peanut butter and beef burger and a cup of coffee for breakfast.'))

这将 POS 标记您的句子并使用正则表达式解析器来提取名词短语。

1.定义和优化你的名词短语正则表达式

您需要更改 模式 正则表达式来定义和优化您的名词短语。 例如,告诉解析器一个 NP 后跟一个协调器 (CC),如 ''and'',另一个 NP 本身就是一个 NP。

2.从 NLTK 词性标注器更改为斯坦福词性标注器

我还注意到 NLTK 的词性标注器表现不佳(例如,它认为 had花生 是动词短语。如果需要,您可以将词性标注器更改为 Stanford Parser。

3.删除较小的名词短语:

在您提取了一个句子的所有名词短语后,您可以删除属于较大名词短语一部分的名词短语。例如,在以下示例中,应该删除 beef burgerpeanut butter,因为 它们是更大的名词短语花生酱和牛肉汉堡的一部分。

4.删除食物词典中没有单词的名词短语

你会得到像school bus这样的名词短语。如果你可以从维基百科或 WordNet 编译的食物词典中没有学校和公共汽车,那么你删除名词短语。在这种情况下,请删除 cupbreakfast,因为它们希望不在您的食物词典中。

当前代码返回

['peanut butter and beef burger', 'peanut butter', 'beef burger', 'cup', 'coffee', 'breakfast']

输入

print(sent_parse('I ate peanut butter and beef burger and a cup of coffee for breakfast.'))

【讨论】:

    【解决方案3】:

    评论太多,但不是真正的答案:

    我认为,如果您在没有适当分隔符的情况下将两种食物组合成一种食物,您至少会更接近。那将提供花生酱、果冻三明治、咖啡。

    如果您的英语正确,您可以通过计数/不计数检测这种大小写。将原文更正为“我早餐吃了一个花生酱和果冻三明治和一杯咖啡”。 Butter 是不可数的,你不能吃“a butter”,但可以吃“a sandwich”。因此 a 必须适用于三明治,尽管“花生酱”和“果冻三明治”必须是同一个项目——“花生酱和果冻三明治”。不过,您的错误句子会以另一种方式解析!

    不过,如果您能提出涵盖所有情况的通用规则,我会感到非常惊讶。我会遇到这种事情,认为有一些会泄漏并需要数据库来捕获。

    【讨论】:

      【解决方案4】:

      您可以在您改变 n 值的文本中搜索 n-gram。例如,如果 n=5,那么您将提取“花生酱和果冻三明治”和“早餐咖啡杯”,这取决于您在文本中开始搜索五个单词组的位置。您不需要文本语料库或数据库来使算法工作。

      【讨论】:

        【解决方案5】:

        使用包含所有食品的词典的基于规则的方法在这里可以使用。

        您可以使用 GATE 并使用 JAPE 规则。

        在上面的例子中,你的 jape 规则有一个条件是在“FOOD LEI​​XCON”中找到所有 (np cc np) && np

        可以在您计划走这条路线的活动中分享详细的 jape 代码。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多