我有一大堆来自网上商店的衣服 每个条目都包含主要字词(例如衬衫,夹克)和一个或多个属性(例如尺寸,颜色)。
衣服可以具有以下属性:
让我们来看一个例子。
SPO SHIRT L
CAS SHIRT M GRE
CAS SHIRT L RED
BUS SHIRT XS RED
CAS SHOES
SHOES BLACK
JACKET FEM M
JACKET FEM GRE
CAS JACKET MA RED
这些项目由人填充,因此不一致。并非每个条目都具有所有属性。他们也可能有不同的命令。
我现在想要自动识别主要单词和属性。另外,我想将上面显示的组中的属性分组。
示例输出只是单词组。
还有属性的类别:
当然,该算法无法为类别(例如大小,颜色)提供合适的名称。
我已经知道的事情:
我可以使用哪些算法来识别这些词?
一种可能的解决方案是使用<=3
字母过滤单词。最有可能的是那些属性。但这是一种相当天真的方法。
我使用JavaScript,但我也感谢伪代码。
这只是列表的一小部分和可能的类别。
更新
我事先不知道这些属性。计算机应该在没有我帮助的情况下提取它们。
答案 0 :(得分:1)
让我们假设每个单词都是主要单词或属性单词 - 也就是说,没有单词有时被用作主要单词,有时也被用作属性。然后问题是将每个单词分类为 main 或属性 - 或等效地,以确定作为主要单词的所有单词的子集(因为其余单词必须是属性词)。我们对属性词不太了解,除了它们应该很常见。但是我们对主要单词的子集有了更明确的认识:每个产品必须在这个子集中只包含一个单词。
此问题可以建模为exact cover,其中地面集(需要的项目集&#34;覆盖&#34;)是所有产品的集合,每个单词都给出我们可以用来覆盖其中一些基本元素的集合:即使用该单词的产品集。这个问题的解决方案将是一个单词的子集,其相应的产品集合在一起包括每个产品一次 - 也就是说,它将是一组候选主词。
不幸的是,找到一个精确的覆盖是一个NP难题,所以没有任何有效的算法可以解决这个问题。
然而,通常情况下,通过将问题表达为integer linear program并使用ILP求解器(例如,等等),可以找到确切的答案或优质的启发式答案。免费提供lp_solve或昂贵(但速度更快)CPLEX来解决问题。有两种方法:
方便地,从一个变为另一个就像指定变量是否被约束为整数一样简单;目标函数和所有约束条件都没有改变。
假设有n个不同的单词和m个产品。为了将这个问题表述为(I)LP,我们将需要一个变量x_j用于每个不同的单词j,如果第j个单词应被视为主要单词,则求解器将赋值1,如果应该被认为是主要单词则为0被认为是一个属性词(或者如果我们只是解决连续放松的话)。如果产品i使用单词j,则令p_i_j为1(该信息存在于输入中,并且可以表示为矩阵)。然后,对于每个产品i,我们需要约束
p_i_1*x_1 + p_i_2*x_2 + ... + p_i_n*x_n = 1.
这迫使产品i只有一个主要词。 (大多数单词不会出现在给定的产品中,因此上述表达式中的相应术语对于p_i_j将具有0值并且可以省略;这样做会大大减少问题描述的大小。)
这些限制是我们实际需要的,但ILP也为我们提供了最小化或最大化的目标函数。因此,我们可以通过尝试最大化(或最小化)函数来找到最大(或最小)的主要单词集
x_1 + x_2 + ... + x_n
这个公式非常灵活:我们可以通过将x_j值约束为0来轻松地对某些单词进行更高的权重,或者防止某些单词(例如出现过于频繁的单词)被视为主要单词。
让我们实际计算所提供的示例数据片段的单词集。
不同的词是:
1 BLACK
2 BUS
3 CAS
4 FEM
5 GRE
6 JACKET
7 L
8 M
9 MA
10 RED
11 SHIRT
12 SHOES
13 SPO
14 XS
[编辑7/3/2016]:我们可以在CPLEX LP format中表达ILP问题,添加一个目标函数(有点随意)最小化选择为主要的单词总数词:
Minimize
x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 + x_8 + x_9 + x_10 + x_11 + x_12 + x_13 + x_14
Subject To
x_13 + x_11 + x_7 = 1
x_3 + x_11 + x_8 + x_10 = 1
x_3 + x_11 + x_7 + x_10 = 1
x_2 + x_11 + x_14 + x_10 = 1
x_3 + x_12 = 1
x_12 + x_1 = 1
x_6 + x_4 + x_8 = 1
x_6 + x_4 + x_5 = 1
x_3 + x_6 + x_9 + x_10 = 1
Binary
x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 x_11 x_12 x_13 x_14
将包含上述代码块的文本文件提交给the online SCIP solver at NEOS,我们返回(据报道在0.00s时间!)一个最佳解决方案,它将3个变量x_6,x_11和x_12分配给1,其余为0:这对应于选择JACKET,SHIRT和SHOES作为主要词语。
在这种情况下,选择最小化被选为主要单词的单词数量可以得到我们认为正确的答案,但一般来说可以有多组满足标准的主要单词,并且它可以不明显如何选择哪个最好。例如,如果我们决定最大化主要单词的数量(正如我最初尝试的那样,FWIW),我们可以得到解决方案{BLACK,BUS,CAS,FEM,SPO}。但总的来说,提供的输入越多,所需的词组就越少,因此目标函数的选择就越少。
在确定哪些单词是主要单词后,我们希望将剩余的属性单词分解为类别。这个问题更难:基本上我们可以说的是,只要两个单词来自同一类别,如CAS和BUS,它们就不能同时出现在同一个产品中。但是,如果这是我们应用的 only 约束,那么一个简单的解决方案就是将每个属性字放入其自己的类别中。当然,这并没有告诉我们任何有用的信息,所以为了避免这种可能性,我们可以要求类别的总数尽可能小。
我们得到的是(Minimum) Graph Colouring问题:对于每个属性词,创建一个顶点,并在任何两个顶点之间创建一个边,只要它们的单词都出现在同一个产品中。图形着色是&#34;颜色的分配&#34; (或等效地,简单地分类)到顶点(单词)总是为边缘的两个端点分配不同的颜色。最小的这种着色使用尽可能少的颜色(类别)。
有几种不同的方法可以将图形着色问题表示为ILP。您可以使用the one given here。请注意,将会有比Exact Cover ILP更多的变量,并且有些配方会有多达k!将特定细分编码为k类的不同方法(基本上,与订购k项的方法一样多的类别分配),因此将此问题解决为最优可能需要更长的时间。
答案 1 :(得分:-1)
<强>更新强>:
记住:在这种情况下,数据越多,算法就越准确。但是如果你只有很少的行具有许多属性,那么几乎每个算法都会失败。对于BLACK而言&gt; = 3的事情也会失败,产品名称是TIE,因此我们必须寻找一个好的算法。
现在我在解决这个问题
解析数据并针对其他唯一单词为每个项目创建每个唯一单词的矩阵。这将为统计数据提供在哪个单位放置中使用哪个单词,并且与该顺序中的单词相关。这也将提供有关在订单中使用单词的频率的统计信息。
我建议创建或(从某处导入)人类可识别颜色名称的列表,因为颜色名称是全局的,如果是蓝色,则会将其写为蓝色。这有助于识别颜色。
一旦确定了颜色,我们就可以寻找性别。当然,如果一个是女性,那么写作的概率可能是F或FEM或FEMALE。因此,我们必须通过任何string matching algorithm找到性别名称中最接近的匹配。
现在定位&lt; = 2个字符单词,它会为您提供尺寸。
然后从剩余的单词中查找最常用的单词,每个频率的出现频率会相当高(因为类别有限),因此设置最小出现次数的阈值以将某些内容识别为类别。
最后剩下的字样是项目名称(衬衫,鞋子等)
此处可能出现的唯一错误是数据非常少或频率阈值未正确优化。
MY_PREVIOUS_ANSWER :(当我认为你只需要解析输入时,这仍然可以用来创建矩阵)。
我认为你可以通过创建地图并迭代它们来解决这个问题,比如
(function () {
"use strict";
const text = `SPO SHIRT L
CAS SHIRT M GRE
CAS SHIRT L RED
BUS SHIRT XS RED
CAS SHOES
SHOES BLACK
JACKET FEM M
JACKET FEM GRE
CAS JACKET MA RED`;
const tokens = {
size_list: "XS, S, M, L, XL".split(', '),
color_list: "GREEN, RED, BLUE, BLACK".split(', ').map((c) => c.slice(0, 3)),
category_list: "SPORT, BUSINESS, CASUAL".split(', ').map((c) => c.slice(0, 3)),
gender_list: ["MA", "FEM", "UNI"],
item_list: "SHOES, SHIRT, JACKET".split(', ')
};
let items = text.split(/\n/).filter((line) => !!line.trim()).map((line) => {
line = line.trim();
let item = {};
line.split(' ').forEach((w) => {
Object.keys(tokens).forEach((t) => {
tokens[t].includes(w) && (item[t.replace('_list', '')] = w);
});
});
return item;
})
document.write(JSON.stringify(items, 0, 4));
}());
&#13;