寻找主词是精确覆盖问题
让我们假设每个词要么是主词,要么是属性词——也就是说,没有词有时用作主词,有时用作属性。然后问题是将每个单词分类为 main 或 attribute - 或者等效地,确定所有单词的子集是主要词(因为其余的必须是属性词)。我们对属性词知之甚少,除了它们应该很常见。但是我们对作为主要词的词子集有更明确的了解:每个产品都必须恰好包含这个子集中的一个词。
这个问题可以建模为找到一个exact cover,其中ground set(需要“覆盖”的项目的集合)是所有产品的集合,每个单词都给了我们一个我们可以潜在的集合用于覆盖其中一些基础元素:即使用该词的产品集。这个问题的一个解决方案是一个词的子集,其对应的产品集一起包含每个产品恰好一次——也就是说,它将是一个候选的主要词集。
不幸的是,找到一个精确的覆盖是一个 NP-hard 问题,所以没有已知的有效算法可以准确地解决这个问题。
整数线性规划的公式
尽管如此,通常可以通过将问题表达为integer linear program 并使用 ILP 求解器(例如免费提供的 lp_solve 或昂贵(但速度更快)CPLEX,来解决问题。有两种方法:
- 使用 integer LP 精确解决问题:这可能需要很长时间,但如果存在则保证找到精确的解决方案。
- 使用普通的连续 LP 启发式地解决问题:这将花费相当短的时间,即使对于较大的输入大小,但通常不会找到可行的解决方案。大多数变量不会被分配 1 或 0,而是会被求解器分配在 [0, 1] 范围内的某个值,这通常可以解释为置信度分数,并简单地四舍五入为 0 或 1。这样做不会'不保证最佳的甚至可行解决方案,但通过执行此四舍五入然后“修复”任何违反可行性(特别是没有指定主词的任何产品)通常可以获得一个好的解决方案,或[EDIT 7/3/2016]任何包含两个或多个主要词的产品)与简单的本地hill-climbing search heuristics。
方便地,从一个更改为另一个就像指定变量是否被约束为整数一样简单;目标函数和所有约束都不会改变。
假设有 n 个不同的词和 m 个产品。要将这个问题表述为 (I)LP,我们需要为每个不同的词 j 设置一个变量 x_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
[EDIT 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 问题:对于每个属性词,创建一个顶点,并在任意两个顶点之间创建一条边,只要它们的词都出现在同一个产品中。图着色是将“颜色”(或等效地,简单的类别)分配给顶点(单词),它总是为边的两个端点分配不同的颜色。最低限度的此类着色使用尽可能少的颜色(类别)。
有几种不同的方法可以将图形着色问题表述为 ILP。你可以使用the one given here。请注意,变量将比 Exact Cover ILP 中的变量多得多,并且对于某些公式,将有多达 k!将特定细分编码为 k 个类别的不同方法(本质上,与排序 k 个项目的方法一样多的类别分配),因此将这个问题解决到最优可能需要更长的时间。