我在表格中存储了大约2M条记录。 每条记录都有一个数字和大约5K布尔属性。
所以表格看起来像这样。
3, T, F, T, F, T, T, ...
29, F, F, T, F, T, T, ...
...
-87, T, F, T, F, T, T, ...
98, F, F, T, F, F, T, ...
我将SUM(A, B)
定义为Ath和Bth属性为真的数字之和。
例如,从上面的示例数据:SUM(1, 3) = 3 + ... + (-87)
,因为第1和第3个属性是T为3和-87
3, (T), F, (T), F, T, T, ...
29, (F), F, (T), F, T, T, ...
...
-87, (T), F, (T), F, T, T, ...
98, (F), F, (T), F, F, T, ...
SUM()
可以使用任意数量的参数:SUM(1)
和SUM(5, 7, ..., 3455)
都是可能的。
是否有一些智能算法可用于查找属性列表L
,其中SUM(L)
会产生最大结果?
显然,对于这个大型数据集来说,强制强制是不可行的。
如果有办法不仅找到最大但是前N个列表,那将是非常棒的。
修改 似乎不可能在没有暴力强迫的情况下找到答案。如果我改变问题以找到“好的估计”,那么有没有好的方法呢? 或者,如果我说L的基数固定为10,那会有办法计算L吗? 我会很开心。
答案 0 :(得分:11)
不幸的是,这个问题是NP-complete。您的选择仅限于使用近似算法找到一个好但非最大的解决方案,或使用分支定界并希望您不会达到指数运行时。
NP完整性证明
为了证明您的问题是NP完整的,我们会将set cover问题减少到您的问题。假设我们有U
个N
个元素集,以及S
M
个U
个子集,S
中所有集合的联合是U
。集合覆盖问题要求T
的最小子集S
,以便U
的每个元素都包含在T
的元素中。如果我们有一个多项式时间算法来解决你的问题,我们可以解决集合覆盖问题如下:
首先,构建一个包含M+N
行和M
属性的表。第一行N
行是“元素”行,每行对应一个U
元素。这些价值“足够负”; -M-1
应该足够了。对于元素行i
,如果j
中j
集中的相应元素不,则S
属性为true。
最后M
行是“设置”行,每行都对应S
中的一个集合。它们的值为1
。对于设置行N+i
,i
属性为 false ,其他所有属性均为真。
元素行的值足够小,以至于排除所有元素行的任何属性选择都会击败包含任何元素行的任何属性。由于S
中所有集合的并集是U
,因此挑选所有属性将排除所有元素行,因此最佳选择属性是包含最多设置行而不包括任何元素行的属性。通过构造表,如果相应集合的并集为U
,则属性选择将排除所有元素行,如果相同,则其得分越少,其包含的属性越少。因此,最佳的属性选择直接对应于S
的最小覆盖。
如果我们有一个好的算法来选择产生最大总和的属性,我们可以将它应用于此表以生成任意S
的最小覆盖。因此,您的问题与NP-complete集合覆盖问题一样困难,您不应该浪费时间来尝试提出一种有效的算法来生成完美的属性选择。
答案 1 :(得分:1)
您可以尝试一种遗传算法方法,从一定(大量)随机属性组合开始,让最差的x%死亡,并通过添加/删除属性来改变剩余人口的一定百分比。
无法保证您会找到最佳答案,但很有可能在合理的时间内找到合适的答案。
答案 2 :(得分:0)
我脑海中没有解决这个问题的多项式算法。我只能建议你一个贪婪的启发式:
对于每个属性,计算其expected_score
,即如果选择单独,它将为SUM带来的加数。在您的示例中,得分1为3 - 87 = -84。
按非递增顺序按expected_score
排序属性。
按照该顺序,贪婪地添加L
属性。调用actual_score
属性a
实际带给您的总和的分数(可能比expected_score
更好或更差,具体取决于L
中已有的属性) 。 如果actual_score(a)
不是严格肯定的,请放弃a
。
这不会给你最优L
,但我认为这是一个“相当不错”的。{/ p>
答案 3 :(得分:0)
注意:请参阅下文,为什么这种方法无法获得最佳效果。
我的第一种方法是从特殊情况L = {}开始(它应该给出所有整数的总和)并将其添加到解决方案列表中。从那里添加可能的属性作为限制。在第一次迭代中,依次尝试每个属性并记住那些给出更好结果的属性。在那次迭代之后,将记住的那些放入解决方案列表中。
在第二次迭代中,尝试为每个记住的属性添加另一个属性。记住那些改善结果的人。从记住的属性组合中删除重复项,并将这些重复项添加到解决方案列表中。请注意,{m,n}与{n,m}相同,因此请跳过多余的组合,以免炸毁你的集合。
重复第二次迭代,直到不再有可能添加的属性来改善最终总和。如果您按其总和订购解决方案列表,则会获得所请求的解决方案。
请注意,有大约20G的方法可以从5k中选择三个属性,因此您无法构建包含这些属性的数据结构,但必须根据需要绝对生成它们。尽管如此,绝对数量可以产生许多临时解决方案,因此您必须有效地存储这些解决方案,甚至可能存储在磁盘上。您可以利用以下事实:您只需要先前迭代的解决方案用于下一次迭代,而不是之前的迭代。
此处的另一个限制是,您最终可能会得到少于N个最佳解决方案,因为不考虑低于L = {}的所有解决方案。在这种情况下,我会接受所有可能的解决方案,直到你有N个解决方案,并且只有当你有N个解决方案丢弃那些没有改善最坏解决方案的解决方案时。
Python代码:
solutions = [{}]
remembered = [{}]
while remembered:
tmp = remembered
remembered = []
for s in remembered:
for xs in extensions(s):
if score(xs) > score(s)
remembered.append(xs)
solutions.extend(remembered)
为什么这不起作用:
考虑一个由三个记录组成的临时解决方案
-2, T, F
-2, F, T
+3, F, F
这些的总和是-1。当我现在选择第一个属性时,我丢弃第二个和第三个记录,总和为-2。当选择第二个属性时,我丢弃第一个和第三个属性,给出相同的-2的总和。当选择第一个和第二个属性时,我丢弃所有三个记录,给出一个零的总和,这是一个改进。