从多个句子中选择或生成规范变体

Posted

技术标签:

【中文标题】从多个句子中选择或生成规范变体【英文标题】:Choose or generate canonical variant from multiple sentences 【发布时间】:2012-06-07 02:02:57 【问题描述】:

我正在使用一个 API,将我的 GTIN/EAN 查询映射到产品数据。

由于返回的数据来自商家产品 Feed,因此几乎普遍存在以下情况:

每个 GTIN 有多个结果 产品的标题几乎是非结构化的 产品标题被“污染” SEO 相关的东西, 关于所含数量的信息, “买二送一”优惠, 等

我正在寻找一种编程方式

选择可用的“最干净”/最规范的版本 生成一个新的表示“最小公分母”。

考虑以下单个 EAN 查询的示例结果:

Nivea Deo 男士干爽滚珠 NIVEA DEO Roll on Dry/blau Nivea Deo Roll-On Dry Impact for Men,50 毫升,3 件装(3 x 50 毫升) Nivea Deo Roll on Dry/blau 50 毫升 Nivea Deoroller 50 毫升干男士 blau Mindestabnahme:6 Stück (1 VE) NIVEA Deoroller,男士干爽效果 NIVEA DEO 滚干/blau_50 毫升

我的自制方法如下所示:

基本清理: 小写标题, 去除过多的空白, 去掉明显的停用词,例如“购买”和“点击” 为word => global occurence 构建一个数组 "Nivea" => 7 "Deo" => 5 "Deoroller" => 2 "VE" => 1 计算每个标题的“累积词值” "Nivea Deo" => 12 "Nivea Deoroller VE" => 10 将累积值除以标题长度,得到一个分数 "Nivea Deo" => 6 "Nivea Deoroller VE" => 3.34

显然,我的方法非常基本,容易出错,并且偏向于使用常用词的短句——产生或多或少令人满意的结果。

您会选择其他方法吗? 有什么 NLP 神奇的方法可以解决我不知道的问题吗?

【问题讨论】:

为什么“购买”和“点击”这两个词不会在您的规范表单中显示为统计上常见的条目? @IraBaxter 更新了问题;) +1 因为你将需要你能获得的所有声誉。 您没有指明结果的预期用途:是显示项目的一般性质(以简洁的形式),在这种情况下“Nivea Deo”是可以的,还是显示具体产品如何区分它和其他可能类似的产品? (在后一种情况下,“Nivea Deo”很糟糕,因为 Nivea 生产了 50 或 100 件可以这样描述的产品。) 您是要独立处理每个 GTIN,还是要检索所有 GTIN 的所有描述,处理所有数据,然后形成所有 GTIN 的结果?您想要一个简洁的结果是否正确,例如货架标签描述(看起来,因为您的所有输入似乎都是这种形式)? 【参考方案1】:

我会:

    将所有字符串转换为小写(或大写) 对所有字符串进行多序列比对 转换回原来的情况 查找每列中出现频率最高的字母 消除间隙

你的例子:

    将所有字符串转换为小写(或大写)

    妮维雅 deo 男士滚珠干爽冲击 妮维雅 deo roll on dry/blau nivea deo 男士干爽滚珠,50 毫升,3 件装(3 x 50 毫升) 妮维雅 deo roll on dry/blau 50 毫升 妮维雅 deoroller 50 毫升干男性 blau mindestabnahme:6 stück (1 ve) nivea deoroller,男士干爽效果 妮维雅 deo roll on dry/blau_50 毫升

    对所有字符串进行多序列比对

    nivea deo roll°°-on°°dry°°°°°°°°°°对男性的影响°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°° nivea deo roll°° on °°dry/blau°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°°°°°° nivea deo roll°°-on°°dry°°°°°°°°°°男士冲击,50 毫升,3er 包装(3 x 50 毫升)°°°°°°° nivea deo roll°° on °°dry/blau °°°°°°°°°°°°°°°°°°°°°°50 ml°°°°°°°°°°°°°°°° °°°°°°°°°°°°°° 妮维雅 deo°roller 50ml 干燥°°°°°°°°°°°°°°°°°男士 blau mindestabnahme: 6 stück (1 ve) nivea deo°roller,°°°°dry°°°°°°°°°°°男性冲击°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°° nivea deo roll°° on °°dry/blau_50 ml°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°

    (其中° 表示间隔字符)

    转换回原来的大小写

    Nivea Deo Roll°°-On °°Dry °°°°°°°°°°°对男性的影响°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°° NIVEA DEO Roll°° on°°Dry/blau°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°°°°°° Nivea Deo Roll°°-On °°Dry °°°°°°°°°°°Impact for Men, 50 ml, 3er Pack (3 x 50 ml)°°°°°°° Nivea Deo Roll°° on °°Dry/blau °°°°°°°°°°°°°°°°°°°°°°50 ml°°°°°°°°°°°°°°°° °°°°°°°°°°°°°° Nivea Deo°roller 50ml 干燥°°°°°°°°°°°°°°°°°男装 blau Mindestabnahme: 6 Stück (1 VE) NIVEA Deo°roller,°°°°Dry °°°°°°°°°°°对男性的影响°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°° NIVEA DEO Roll°° on °°Dry/blau_50 ml°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°

    在每一列中查找出现频率最高的字母

    Nivea Deo Roll°° on °°Dry °°°°°°°°°°°°°°°°°°男用°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°°°

    消除间隙

    Nivea Deo 男士干爽卷

除了第 2 步(多序列比对)之外的所有操作都很简单。多序列比对通常用于生物信息学,参见例如。 here 或 here 或 here... 你当然可以找到 C 或 Java 代码,但我不确定 php

更新:

为了让您开始进行多重对齐,所谓的“星形对齐”基本上是一个序列(“星形中心”)与其他序列的成对对齐的组合。成对对齐通常使用动态编程计算,参见例如here 或 here。要产生多重对齐,您可以选择一根弦作为星形中心。你找到它和其他所有字符串之间的成对对齐,然后通过在它们中引入间隙来对齐成对对齐,以便所有对齐中的星形中心完美对齐。您可以将上一步的结果作为下一步的星中心重复该过程,直到收敛,即结果不变。

更新 2: 您还可以使用整个单词作为符号(quants、atoms)来对齐。比如,A = niveaB = deo 等。这有以下优点:

    单词不能通过对齐方式进行更改,并且无论其长度如何,都一视同仁 在进行成对对齐时,您可以根据 TF-IDF 及其同义词分配替换单个单词(“符号”)的成本。成对比对试图最小化(加权)序列之间的 Levenshtein 距离。

在您的示例中(自己尝试),这将导致

Nivea Deo Roll on Dry for Men 50 ml

即我们也到了50 ml。这是因为跳过两个字母的单词并不比跳过 20 个字母的单词便宜。

【讨论】:

感谢您的时间和精力——我非常喜欢生物信息学方法,将名称视为“突变基因”似乎是正确的做法。不过,在查看实施成本时,@adi92 的答案似乎更可行。【参考方案2】:

你有一个非常好的 NLP 问题。大约一年前,我做过类似的工作。我也会推荐 adi92 的方法。但如果您需要使用任何 NLP 软件,我建议您使用斯坦福 NLP。该软件和相应的出版物也在这里。 http://nlp.stanford.edu/希望这会有所帮助。

【讨论】:

【参考方案3】:

如果我理解正确,您并没有将这些名称与现有数据库进行匹配,而是试图尽可能接近产品的实际名称,所以这是我的想法:

    不要进行通常的清理 - 只需删除多余的空格 - 保留停用词、字符大小写、分隔符(如连字符)不变。 将字符串拆分为空格。 在分隔符、数字/字符、字符大小写上拆分词条,但不要删除原始词条,只需在拆分词条之后添加其他词条,小写所有词条,删除重复和空词条 删除对于固定百分比的字符串不常见的术语(如果它应该是 40% 或 95%,您会在测试后知道) - 这将删除商家添加的大部分内容(如果不是全部的话)。 查找每个术语最常见的位置。 如果您获得多个具有相同最常见位置的术语,请检查哪一个在另一个之前更常见。将“宽松”位置增加 1,重复直到没有冲突 对于剩下的每个术语,选择最常用的大写形式 合并剩余条款

使用您的示例,它会像这样工作:

第 1 步:

Nivea Deo Roll-On Dry Impact for Men

NIVEA DEO Roll on Dry/blau

Nivea Deo Roll-On Dry Impact for Men,50 毫升,3 件装(3 x 50 毫升)

Nivea Deo Roll on Dry/blau 50 毫升

Nivea Deoroller 50 毫升干男士 blau Mindestabnahme:6 Stück (1 VE)

NIVEA Deoroller,男士干爽效果

NIVEA DEO Roll on Dry/blau_50 毫升

第 2 步:

Nivea、Deo、Roll-On、Dry、Impact、for、Men

NIVEA、DEO、Roll、on、Dry/blau

Nivea, Deo, Roll-On, Dry, Impact, for, Men, 50, ml, 3er, Pack, (3, x, 50, ml)

Nivea, Deo, Roll, on, Dry/blau, 50, ml

Nivea, Deoroller, 50ml, dry, for, Men, blau, Mindestabnahme:, 6, Stück, (1, VE)

NIVEA,Deoroller,Dry,Impact,for,男士

NIVEA、DEO、Roll、on、Dry/blau_50、ml

第 3 步:

妮维雅、deo、roll-on、roll、on、dry、impact、for、men

妮维雅,deo,滚,上,干/蓝,干,蓝

妮维雅、deo、roll-on、roll、on、dry、impact、for、men、50、ml、3er、pack、3、x、50、ml

nivea, deo, roll, on, dry, blau, 50, ml

nivea, deoroller, 50ml, 50, ml, dry, for, men, blau, mindestabnahme, 6, stück, 1, ve

妮维雅,脱脂剂,干燥,冲击,男士

nivea, deo, roll, on, dry/blau, 干, blau, 50, ml

第 4 步:(假设阈值为 60%)

nivea, deo, roll, on, dry, for, men

妮维雅,deo,滚,上,干,蓝

nivea, deo, roll, on, dry, for, men, 50, ml

妮维雅,deo,卷,上,干,50,毫升

妮维雅,50,毫升,干,男士,蓝色

妮维雅,干,男士

nivea, deo, roll, on, dry, blau, 50, ml

第 5 步:

妮维雅 => 1

deo => 2

滚动 => 3

开 => 4

干 => 5

对于 => 6

男人 => 7

蓝=> 6

50 => 8、6、2、7

ml => 8, 7, 3, 8

第 6 步:

妮维雅 => 1

deo => 2

滚动 => 3

开 => 4

干 => 5

蓝=> 6

对于 => 7

男人 => 8

50 => 9

毫升 => 10

第 7 步

Nivea, Deo, Roll, on, Dry, blau for, Men, 50, ml

第 8 步

最终结果:Nivea Deo Roll on Dry blau for Men 50 ml

此方法存在以下问题:

    它不能很好地处理具有重复术语的名称(或根本无法处理 - 第一个之后的所有术语都丢失了) 倾向于将连字符分隔或大小写分隔 (ProductName) 的名称部分拆分为空格分隔的部分 - 如果您在第 8 步检查最常见的版本,则可以解决此问题。

【讨论】:

感谢您的回答!您的方法看起来很有趣,并且可能非常适合返回大量结果的情况!只是出于好奇:你是自己想出这个的还是它是一种被接受/常见的方法?如果是后者,如果您添加某种参考,我将不胜感激。 这是我自己的解决方案 - 在我将结果提供给正则表达式之前,我曾经使用它来标准化来自多个大型数据库的用户输入数据。确实,如果您有多个输入值,则效果最好 - 我平均有 30 条记录。 再次感谢您的有趣方法 - 我决定将赏金奖励给 @adi92,因为他的方法不太依赖于输入集的大小。不过你的紧随其后——可惜我不能分红:/【参考方案4】:

由于您现有的指标似乎偏向于较短的短语,因此您应该考虑将二元组考虑在内。因此,不要只考虑单个单词的分数,还要考虑连续单词对的分数(例如,'nivea deo'、deo roll-on'、'roll-on dry' 等)。在计算每个标题的分数时,将您可以从标题中生成的每个 unigram 和 bigram 的分数考虑在内,但可能会给 bigrams 更多的权重,这应该会鼓励您的算法更喜欢更长的短语。

如果您有大量此类名称的现有大型语料库可供您使用,请考虑使用类似 TF-IDF 你做对的事情可以比作只是使用 TF。使用您的全局语料库,您可以计算每个 unigram 和 bigram 的 idf,这基本上是衡量一个单词或短语在整个语料库中的唯一性或稀有性。 tf = 您在这些结果中看到 ngram 的次数 idf = 衡量一个 ngram 在所有结果(或至少非常多的结果)中的独特性的全局度量 因此,在计算标题的分数时,不是简单地将其中每个 ngram 的 tf 相加,而是将每个 ngram 的 tf*idf 相加。较稀有的 ngrams(可能更好地将该项目与所有其他项目区分开来)具有更高的 idf,因此您的算法应该赋予它们更高的权重。许多垃圾术语(如 Mindestabnahme)的 idf 非常高,但它们的 tf 非常小,因此它们可能不会产生太大的影响。或者修剪掉你看到少于 k 次的标记,以消除噪音。

另一个需要了解的 NLP 技巧是 Levenshtein distance .. 这是一种量化两个字符串相似程度的方法。您可以计算结果中每对字符串之间的 levenshtein 距离,然后尝试选择与所有其他字符串具有最低平均距离的结果。这本身可能效果不佳......但是将这个分数与您现有的方法结合起来可能会帮助您解决一些棘手的情况。

【讨论】:

感谢您的回答。我选择了您的方法而不是其他方法,因为它在输入集大小方面的简单性和灵活性。如果您能稍微扩展您的答案以供将来参考,我将不胜感激(即像其他人一样,一个简单的计算示例)。 当然。我明天会在我的帖子中添加一些示例计算。我的答案只是列出了 3 个教科书 NLP 技巧,它们可以帮助您在收集更多数据时使您现有的解决方案越来越好用。你有没有在你的数据上尝试过这些想法?请随时提出更多问题。您应该在您的问题中向我们提供更多示例输入。仅提供 1 个样本输入会鼓励解决方案在此特定情况下可能非常有效,但对于您的系统必须处理的大多数其他输入(过度拟合)来说效果不佳。

以上是关于从多个句子中选择或生成规范变体的主要内容,如果未能解决你的问题,请参考以下文章

如果仅句子包含搜索列表中的任何关键字,则从数据框文本列中选择句子

将一个句子分为多个类别

从 WooCommerce 可变产品的变体中自动选择第一个可用选项

具有多种变体的 Foreach 字符串替换

如何在python中选择异步或同步方法变体?

如何获取 Sharepoint (MOSS) 2007 中的当前语言或变体?