【问题标题】:Efficient way to get union of set of vectors in Numpy在 Numpy 中获得向量集并集的有效方法
【发布时间】:2018-12-28 04:35:41
【问题描述】:

我正在尝试实现特定的二进制搜索算法。 “Results”一开始应该是一个空集,在搜索过程中,Results变量会和我们得到的新结果成为一个union。

基本上:

results = set()
for result in search():
  results = results.union(result)

但是这样的代码并不能真正用于 Numpy 数组,所以我们使用 np.union1d 来达到这个目的:

results = np.array([])
for result in search():
    result = np.union1d(results, result)

上面的代码也不起作用,因为如果我们有两个向量 a = [1,2,3]b=[3,4,5]np.union1d(a, b) 将返回:

[1, 2, 3, 4, 5]

但我希望它返回:

[[1, 2, 3], [3,4,5]]

由于没有重复的向量,如果我们有例如union([[1, 2, 3], [3,4,5]], [1,2,3]),则返回值应保持:

[[1, 2, 3], [3,4,5]]


所以我会说我需要一个基于numpy数组的联合

我也考虑过使用np.append(a, b),然后使用np.unique(x),但是这两个函数都将低维数组投影到高维数组。 np.append 也有 axis=0 属性,它保留所有插入的数组的维度,但我无法有效地实现它而不会出现维度错误。

问题:

如何有效地实现基于向量的集合?这样联合中的点将被视为向量而不是标量,并将保留它们的向量形式和维度。

【问题讨论】:

  • 如何将数组转换为元组? tuple(arr.tolist())。 Python set 需要可散列的对象,例如 tuples
  • @hpaulj tolist() 方法不是让算法效率更低吗?我试过将这样的元组附加到数组中,它们大大增加了时间。由于出现“不可散列类型”错误,我无法尝试使用集合。
  • @Kasrâmvd 我确实尝试过 np.unique 提到的(轴参数也是如此),但我不确定如何有效地为高维数组实现它。 (即如何定义初始向量而不出现尺寸错误)
  • set 如果你可以给它像元组这样的可散列对象,那么它是非常有效的。 numpy 集合函数一般使用np.unique,它是基于对元素进行排序。 unique 最初使用一维数组,np.union1d 仍然如此。它已被扩展为采用 axis 参数,但其核心仍然是一维排序。

标签: python arrays numpy


【解决方案1】:

这里有一些基本的集合操作。

定义一对列表(它们可以是np.array([1,2,3]),但这不是您显示的内容。

In [261]: a = [1,2,3]; b=[3,4,5]

其中几个列表:

In [263]: alist = [a, b, a]
In [264]: alist
Out[264]: [[1, 2, 3], [3, 4, 5], [1, 2, 3]]

我可以通过转换为元组并将它们放在set 中来获得唯一值。

In [265]: set([tuple(i) for i in alist])
Out[265]: {(1, 2, 3), (3, 4, 5)}

我还可以将该列表转换为二维数组:

In [266]: arr = np.array(alist)
In [267]: arr
Out[267]: 
array([[1, 2, 3],
       [3, 4, 5],
       [1, 2, 3]])

并使用unique 和轴参数获取唯一行:

In [269]: np.unique(arr, axis=0)
Out[269]: 
array([[1, 2, 3],
       [3, 4, 5]])

比较时间

In [270]: timeit np.unique(arr, axis=0)
46.5 µs ± 142 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [271]: timeit set([tuple(i) for i in alist])
1.01 µs ± 1.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

将数组转换为列表或将列表转换为数组会增加一些时间,但基本模式仍然存在。

In [272]: timeit set([tuple(i) for i in arr.tolist()])
1.53 µs ± 13.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [273]: timeit np.unique(alist, axis=0)
53.3 µs ± 90.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

对于更大、更现实的源,相对时间可能会有所变化,但我希望元组集仍然是最好的。集合操作不是numpy 的强项。 unique 进行排序,然后消除重复项。 set 使用散列方法,类似于 Python 用于字典的方法。

如果您必须从 source 迭代地收集值,我建议您建立一个列表,然后执行一次 set/unique

alist = []
for x in source():
    alist.append(x)

或其中之一:

alist = [x for x in source()]
alist = list(source())
alist = [tuple(x) for x in source()]
alist = [tuple(x.tolist()) for x in source()]

【讨论】:

  • 是的,我试过了,而且速度更快。尽管将 numpy 数组转换为元组需要一些时间,因此我将 source() 制作一个充满元组的列表,以便它们是预先定义的。谢谢!
猜你喜欢
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-21
  • 2016-06-22
  • 2019-12-01
  • 2012-08-12
  • 1970-01-01
相关资源
最近更新 更多