【问题标题】:Optimize finding pairs of arrays which can be compared优化查找可以比较的数组对
【发布时间】:2013-02-05 14:32:09
【问题描述】:

定义:数组 A(a1,a2,...,an)>=B(b1,b2,...bn) 如果它们大小相等,则 a_i>=b_i 对于每个 i1n.

例如:

[1,2,3] >= [1,2,0]
[1,2,0] not comparable with [1,0,2]
[1,0,2] >= [1,0,0]

我有一个列表,其中包含大量此类数组(大约 10000,但可以更大)。数组的元素是正整数。我需要从这个列表中删除所有比至少一个其他数组大的数组。换句话说:如果存在这样的B A >= B 然后删除A

这是我目前的O(n^2) 方法,它非常慢。我只是将每个数组与所有其他数组进行比较,如果它更大,则将其删除。有什么方法可以加快速度。

import numpy as np
import time
import random

def filter_minimal(lst):
    n = len(lst)
    to_delete = set()
    for i in xrange(n-1):
        if i in to_delete:
            continue
        for j in xrange(i+1,n):
            if j in to_delete: continue
            if all(lst[i]>=lst[j]):
                to_delete.add(i)
                break
            elif all(lst[i]<=lst[j]):
                to_delete.add(j)
    return [lst[i] for i in xrange(len(lst)) if i not in to_delete]


def test(number_of_arrays,size):
    x = map(np.array,[[random.randrange(0,10) for _ in xrange(size)] for i in xrange(number_of_arrays)])
    return filter_minimal(x)

a = time.time()
result = test(400,10)
print time.time()-a
print len(result)

附:我注意到使用 numpy.all 而不是内置的 python all 会大大降低程序的速度。可能是什么原因?

【问题讨论】:

  • 所以你想要最小的数组?你怎么处理无法比较的数组...我没有关注...
  • 没有。我需要删除所有与较小数组相比的数组。例如:List([1,2,3], [1,2,1], [1,0,2])。我需要删除 [1,2,3],因为它大于 [1,2,1]。但是,我无法对 [1,0,2] 做任何事情,因为它无法与任何其他数组进行比较。
  • 那么最后,您只剩下无法相互比较的数组了吗?
  • 是的!正是我需要的。这是用于求解丢番图方程组的 TSS 算法的一部分。
  • 为什么[1,2,0][1,0,2] 没有可比性?只是前 n-1 个索引不相等?另一个需要考虑的O(N^2) 方法,但可能更快,是使用更高维的 numpy 数组而不是所有这些循环。

标签: python algorithm optimization numpy


【解决方案1】:

可能不是您所要求的,但这应该可以帮助您入门。

import numpy as np
import time
import random

def compare(x,y):
    #Reshape x to a higher dimensional array
    compare_array=x.reshape(-1,1,x.shape[-1])
    #You can now compare every x with every y element wise simultaneously
    mask=(y>=compare_array)
    #Create a mask that first ensures that all elements of y are greater then x and
    #then ensure that this is the case at least once.
    mask=np.any(np.all(mask,axis=-1),axis=-1)
    #Places this mask on x
    return x[mask]

def test(number_of_arrays,size,maxval):
    #Create arrays of size (number_of_arrays,size) with maximum value maxval.
    x = np.random.randint(maxval, size=(number_of_arrays,size))
    y=  np.random.randint(maxval, size=(number_of_arrays,size))
    return compare(x,y)

print test(50,10,20)

【讨论】:

  • 嗯,很好的矢量化方法,但这仍然是 O(N^2)。如果我没有找到更好的东西,我可能会用纯 C 重写那个函数。
  • 充其量你会有 O(N log(N)) 缩放到这个,我相信所需想法的唯一实现是 scipy KDTree,但当然不会做你想做的事做。 AFAIK 在 numpy 或 scipy 中没有任何东西可以满足您的需求,如果您担心速度,最好用 C 编写。
【解决方案2】:

首先我们需要仔细检查目标。我们是否删除了任何大于其他数组的任何数组,甚至是已删除的数组?例如,如果 A > B and C > A and B=C,那么我们需要只删除 A 还是同时删除 A 和 C?如果我们只需要删除 INCOMPATIBLE 数组,那么这是一个更难的问题。这是一个非常困难的问题,因为这组数组的不同分区可能是兼容的,所以你遇到了找到最大有效分区的问题。

假设问题很简单,定义问题的更好方法是您希望保留所有具有至少一个元素的数组

第一阶段

要解决这个问题,您要做的是将数组按列排列,然后对每一行进行排序,同时保持数组的键和每个数组行到位置的映射(位置列表)。例如,您可能会在第 1 阶段得到如下结果:

第 1 行:B C D A E
第 2 行:C A E B D
第 3 行:E D B C A

表示对于第一个元素(第 1 行)数组 B 的值 >= C、C >= D 等。

现在,对该矩阵的最后一列进行排序和迭代(示例中为 {E D A})。对于每个项目,检查元素是否小于其行中的前一个元素。例如,在第 1 行中,您将检查是否 E

在显示的示例中,您将保留 E、D、A(只要它们通过了上述测试)。

第二阶段

剩下 B 和 C。对每个位置列表进行排序。例如,这会告诉你 B 的最小位置所在的行是第 2 行。现在直接比较 B 和它下面的最小行中的每个数组,这里是第 2 行。这里只有一个这样的数组,D。 B 和 D 之间的直接比较。这表明第 3 行中 B

现在我们对 C 做同样的事情。在 C 的情况下,我们只需要与 A 进行一次直接比较。C 支配 A,所以我们不保留 C。

请注意,除了测试未出现在最后一列中的项目之外,我们还需要测试阶段 1 中相等的项目。例如,假设第 1 行中的 D=A=E。在这种情况下,我们必须对最后一列中涉及数组的每个等式进行直接比较。因此,在这种情况下,我们直接将 E 与 A 和 E 与 D 进行比较。这表明 E 支配 D,因此不保留 E。

最终的结果是我们保留了A、B、D。C和E被丢弃了。

这个算法的整体性能是n2*log n in Stage 1 + { n lower bound, n * log n - upper bound } 在Stage 2. 所以,最大运行时间是n2*log n + nlogn 和最小运行时间时间是 n2logn + n。请注意,您的算法的运行时间是 n 立方 n3。由于您比较每个矩阵(n * n)并且每个比较是n个元素比较= n * n * n。

一般来说,这将比蛮力方法快得多。大部分时间将花费在对原始矩阵进行排序上,这是或多或少不可避免的任务。请注意,您可以通过使用优先级队列而不是排序来改进我的算法,但生成的算法会复杂得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-22
    • 2015-05-16
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    相关资源
    最近更新 更多