我有2d数组。我需要从每列中选择一个最佳集合。
最佳集合使得所有此类最佳集合中的唯一项目数量最少。
我正在使用python,但我相信这应该是与语言无关的。
我当前的方法非常原始,并搜索所有可能的选项,这可能会创建一个非常大的搜索空间。 (10 ^ 15的顺序)
我正在寻找一种不那么天真的方式来查看数据,并减少搜索空间。
在下面的代码中,我知道我可以改进性能,但我对改进算法更感兴趣。
for comb in itertools.product(*value_options):
comb_length = len(set(itertools.chain(*comb)))
if comb_length < best_count:
best = comb
best_count = comb_length
关于数据的更多信息,集合很小,目前它们是两个值,但我希望能够支持更多,一组集合中可以有任意数量的集合
我添加了一些测试数据。为了使文件更符合逻辑,文件中的每一行都是上面提到的列之一,每个集都在父集中。
小集 http://www.importsoul.net/static/testdata.csv
从这组数据中我得到了结果
332000.000,348000.000
95300.000,787000.000
48700.000,332000.000
31600.000,64900.000
12700.000,64900.000
5620.000,95300.000
10000.000
我还有一组更大的输入数据尚未完成运行。 http://www.importsoul.net/static/testdata-large.csv
为了便于导入,测试数据为json
答案 0 :(得分:1)
这个问题是NP完全的。你可以做得比你现在拥有的更好,但是你可以扩展到多远。
首先,您可以使用branch-and-bound来改进您的算法,以避免查看“明显”比您已经看到的更差的解决方案。我们的想法是跟踪到目前为止看到的最佳解决方案所涵盖的独特元素的数量,并通过一次从一列中选择集合来构建部分解决方案。如果在任何时候,您选择的集合涵盖了比您看到的最佳解决方案更多的独特元素,您可以立即撤消最近的选择并尝试不同的选项,而无需探索构建完整解决方案的所有可能方法从次优的部分解决方案。
为了证明问题是NP完全的,我们提供了从boolean satisfiability到你的问题的多项式时间减少。我们假设列可以有不同的长度;证据稍微有点尴尬,但仍然可能,列被迫等长。
假设我们有一个联合正规形式的布尔公式,例如:
(!A || B || C) && (!C || D || !E) && (A || !B || D)
我们想知道它是否令人满意。我们构建了一个相应的问题实例。我们的想法是使用1元素集的列强制自己为每个变量选择一个真值,看看我们是否可以选择集合,使得变量不能同时为真和假。
对于公式中的每个析取子句,我们构造一个列,强制我们选择析取的一个元素。例如,析取句(!A || B || C)
将变为列
{!A}
{B}
{C}
迫使我们选择分离给我们的一个选择。另外,我们添加以下形式的列:
{A} | {B} | {C} | {D} | {E}
{!A} | {!B} | {!C} | {!D} | {!E}
强迫我们为每个变量选择变量或其否定。我们的示例公式的完整表格如
{!A} | {!C} | {A} | {A} | {B} | {C} | {D} | {E}
{B} | {D} | {!B} | {!A} | {!B} | {!C} | {!D} | {!E}
{C} | {!E} | {D}
如果每列的最佳集合选择涵盖了与公式中变量数量相等的多个唯一元素,那么最佳选择的元素为公式提供了令人满意的赋值。如果集合的最佳选择涵盖的元素多于该集合,则该公式是不可满足的。