解析食谱的自然语言成分数量

时间:2012-09-13 19:48:48

标签: ruby regex nlp nltk wolframalpha

我正在构建一个ruby配方管理应用程序,作为其中的一部分,我希望能够将成分数量解析为我可以比较和扩展的形式。我想知道这样做的最佳工具是什么。

我最初计划使用复杂的正则表达式,然后使用其他代码将twofive等人类可读数字转换为整数,最后将代码转换为1 cup和{ {1}}进入一些基础测量。我控制输入,所以我将实际成分分开。但是,我注意到用户输入了3 teaspoonsto taste等抽象测量值。至少在抽象测量中,我想我可以忽略它们并进行缩放,只是刮掉它们之前的任何数字。

以下是更多示例

1 package

这有什么窍门吗?我注意到用户似乎对构成数量的内容感到困惑。我可以尝试执行更严格的规则,并将1 tall can 1/4 cup 2 Leaves 1 packet To Taste One Two slices 3-4 fillets Half-bunch 2 to 3 pinches (optional) tall can等内容推送到组成部分。但是,为了强制执行,我需要能够传达无效的内容。

我可以使用api或gem吗? WolframAlpha最初看起来很有希望,但最终,我不认为它会起作用,除非我能告诉他们我只给他们提供食谱数量。

我也不确定我应该将数量转换为“基础”测量值。

编辑:只是为了解决任何困惑,这些是我的目标。

  1. 能够扩展食谱。任意的测量单位 leaves不必缩放,而是精确的packages或。cups ounces需要成为。

  2. 弄清楚“主要”成分。在这个问题的背景下,这将主要通过弄清楚配方中最大的成分是什么来完成。在生产中,必须有一些基于成分类型的改性剂,因为很明显,flour几乎从未被认为是“主要”成分。但是,chocolate可以谨慎使用,仍然可以说是chocolate cake

  3. 规范化输入。为了保持网站的一致性,我希望保留一致的缩写。例如,代替pounds,它应该是lbs

  4. 我还添加了NLTK标记,因为我想知道在使用NLTK的python中这样做是否更容易。

4 个答案:

答案 0 :(得分:20)

你提出两个问题,识别/提取数量表达式(语法)并弄清楚它们的含义(语义)。

在你弄清楚正则表达式是否足以识别数量之前,你应该让自己成为一个好的模式(语法)。您的示例如下所示:

<amount> <unit> [of <ingredient>]

其中<amount>可以有多种形式:

whole or decimal number, in digits (250, 0.75)
common fraction (3/4)
numeral in words (half, one, ten, twenty-five, three quarters)
determiner instead of a numeral ("an onion")
subjective (some, a few, several)

金额也可以表示为两个简单<amount> s的范围:

two to three
2 to 3
2-3
five to 10

然后你自己拥有单位:

general-purpose measurements (lb, oz, kg, g; pounds, ounces, etc.)
cooking units (Tb, tsp)
informal units (a pinch, a dash)
container sizes (package, bunch, large can)
no unit at all, for countable ingredients (as in "three lemons")

最后,有一个特殊情况的表达式永远不能与金额或单位组合,因此它们有效地作为两者的组合起作用:

a little
to taste

我建议将其作为一个小解析器来处理,您可以根据需要进行详细或粗略的处理。如果这是你选择的工具,那么为所有这些编写正则表达式应该不会太难,但正如你所看到的那样,这不仅仅是文本替换的问题。拉出零件并将每种成分表示为三重(amount, unit, ingredient)。 (对于可数,使用特殊单位“碎片”或其他;对于“一点点”等,我会将它们视为特殊单位。)

这留下了转换或比较数量的问题。单位转换已在很多地方完成,因此至少对于官方单位,您应该可以轻松获得转换表。例如,如果您键入“将4oz转换为克数”,谷歌就会这样做。请注意,根据国家/地区,Tbsp为either three or four tsp

对于明确定义的单位,您可以非常轻松地将您喜爱的单位标准化,但非正式单位有点棘手。对于“捏”,“破折号”等,我建议找出近似的重量,以便你可以正确缩放(十捏= 2克,或其他)。除非您能查看特定产品的尺寸,否则罐头等无望。

另一方面,主观量是最容易的:如果你扩大“尝试”十次,它仍然是“品尝”!

最后一个想法:识别主要成分还需要某种成分数据库,因为尺寸很重要:“一个鸡蛋”可能不是主要成分,而是“一只小山羊,四分之一“很可能是。我认为它适用于版本2.

答案 1 :(得分:9)

正则表达式很难用于自然语言解析。 NLTK,就像你提到的那样,可能是一个很好的选择,否则你会发现自己绕圈子试图让表达正确。

如果你想要一些Ruby品种而不是NLTK,请看看Treat:

https://github.com/louismullie/treat

此外,语言学框架也可能是一个不错的选择:

http://deveiate.org/projects/Linguistics

修改

我认为那里必须有一个Ruby配方解析器,这是您可能想要研究的另一个选项:

https://github.com/iancanderson/ingreedy

答案 2 :(得分:6)

如果您知道如何编写优秀的Web抓取工具和解析工具,那么可以获得大量免费的培训数据。

http://allrecipes.com/Recipe/Darias-Slow-Cooker-Beef-Stroganoff - 此网站似乎允许您根据公制/英制系统和用餐人数转换配方数量。

http://www.epicurious.com/tools/conversions/common - 此网站似乎有很多转换常量。

对现有配方网站进行一些系统性的抓取,这些网站以一些结构化的格式呈现成分,程序(通过阅读底层的html可以发现)将帮助您构建一个非常大的训练数据集,这将使得解决这样的问题更多更容易。

当您拥有大量数据时,即使是简单的学习技巧也非常有用。一旦掌握了大量数据,就可以使用标准的nlp技巧(ngrams,tf-idf,朴素的bayes等)快速做出很棒的事情。

例如:
主要成分
具有较高idf(逆文档频率)的菜中的成分更可能是主要成分。每道菜都提到盐,所以它应该有非常低的idf。少量菜肴提油,所以应该有更高的idf。大多数菜肴可能只有一种主要蛋白质,所以“鸡肉”,“豆腐”等词语应该比较少,而且比盐,洋葱,油等更有可能成为主要成分。当然可能有像'香菜这样的食物'这可能比'鸡'更罕见,但是如果你已经把每一道菜的相关元数据都删掉了,那么你将有信号帮助你解决这个问题。大多数厨师可能没有在他们的食谱中使用香菜,但那些可能会使用它的人非常多。因此,对于任何成分名称,您可以首先考虑至少一次提到该成分的作者,然后在该食谱子集中查看成分的idf,从而找出名称的idf。

扩展食谱
大多数食谱网站都提到了特定菜肴的供应人数,并且为这个数量的人提供了适当数量的单独成分列表 对于任何特定成分,您可以收集提及它的所有食谱,并查看为多少人配定的成分数量。这应该告诉您用什么短语来描述该成分的数量,以及数字如何缩放。此外,您现在可以收集所有使用特定短语描述数量的成分(例如'切片' - >(面包,奶酪,豆腐......),'杯' - >(米饭,面粉,坚果, ...))并查看最常见的这些短语,并手动写下它们如何扩展。

规范化输入
这似乎不是一个难题。手动策划常用缩写及其完整形式的列表(例如'lbs' - &gt;'磅','kgs' - &gt;'千克','oz' - &gt;'盎司'等)应解决90%的问题。每当你看到它们时,在这个列表中添加新的收缩应该会使这个列表在一段时间后非常全面。

总而言之,我要求您主要增加数据的大小,并收集大量相关元数据以及您抓取的每个食谱(作者信息,食物类型等),并使用所有这些结构化数据以及简单的NLP / ML技巧可以解决您在尝试构建智能配方网站时遇到的大多数问题。

答案 3 :(得分:0)

就这些而言:

  1. 我会对这些进行硬编码,这样如果你得到的咖啡数量超过这么多,就去杯子,如果你得到多少杯子,那就去品脱,窝,加仑等。我不会知道如何避免这种情况,除非有人已经编写了代码来处理这个问题。

  2. 如果标题中含有一种成分,它可能是主要成分。但是你会遇到“燕麦葡萄干饼干”的问题。正如你所说,面粉,牛奶等不是主要成分。您还需要将培根,猪排,猪肉烤到猪肉,牛排,汉堡包等都用牛肉。

  3. 再一次,这只是查看一些东西,你知道人们会有lbs,oz等,所以尽量抢占它们并尽可能地写出来。您可能会错过一些,但随着您网站的增长,您将能够引入新的过滤器。

  4. 如果您完成所有这些工作,请考虑将其释放,以便其他人不必:)