【问题标题】:Python: efficient way to match 2 different length arrays and find index in larger arrayPython:匹配2个不同长度数组并在更大数组中查找索引的有效方法
【发布时间】:2015-08-19 14:11:24
【问题描述】:

我有 2 个数组:xbigx。它们跨越相同的范围,但bigx 有更多的点。 例如

x = np.linspace(0,10,100)
bigx = np.linspace(0,10,1000)

我想在bigx 中找到索引,其中xbigx 匹配2 个有效数字。我需要非常快地做到这一点,因为我需要积分的每一步的索引。

使用numpy.where 很慢:

index_bigx = [np.where(np.around(bigx,2) == i) for i in np.around(x,2)]

使用numpy.in1d 的速度提高了约 30 倍

index_bigx = np.where(np.in1d(np.around(bigx), np.around(x,2) == True)

我也尝试使用 zipenumerate,因为我知道这应该更快,但它返回空:

>>> index_bigx = [i for i,(v,myv) in enumerate(zip(np.around(bigx,2), np.around(x,2))) if myv == v]
>>> print index_bigx
[]

我想我一定是把这里的东西弄糊涂了,我想尽可能地优化它。有什么建议?

【问题讨论】:

  • numpy.in1d 从您尝试过的列出的可能性中看起来是最优化的方式。
  • 是的,但是对于我的目的来说它仍然太慢了。我希望有人可以提出另一种有效的 pythonic 方式来做到这一点。
  • xbigx 是否总是统一的(就像在您的示例中一样)?他们总是排序吗?
  • 是否期望数组像示例中那样均匀分布?另外,around(0.0049, 2) != around(0.0051, 2);这些应该被认为是匹配的吗?
  • 两个数组总是排序的。 bigx 总是均匀分布的(而且它是固定的),x 不是均匀分布的,它是一个变化的变量 - 因此我希望这种匹配有效,因为我必须多次这样做。

标签: python arrays performance numpy matching


【解决方案1】:

由于bigx 始终是均匀分布的,因此直接计算索引非常简单:

start = bigx[0]
step = bigx[1] - bigx[0]
indices = ((x - start)/step).round().astype(int)

线性时间,无需搜索。

【讨论】:

  • 智能接近这个!
  • 谢谢!简单快速!它消除了 np.around 的错误
【解决方案2】:

由于我们将x 映射到其元素等距的bigx,因此您可以使用np.searchsorted 的分箱操作来模拟使用其'left' 选项的索引查找操作。这是实现 -

out = np.searchsorted(np.around(bigx,2), np.around(x,2),side='left')

运行时测试

In [879]: import numpy as np
     ...: 
     ...: xlen = 10000
     ...: bigxlen = 70000
     ...: bigx = 100*np.linspace(0,1,bigxlen)
     ...: x = bigx[np.random.permutation(bigxlen)[:xlen]]
     ...: 

In [880]: %timeit np.where(np.in1d(np.around(bigx,2), np.around(x,2)))
     ...: %timeit np.searchsorted(np.around(bigx,2), np.around(x,2),side='left')
     ...: 
100 loops, best of 3: 4.1 ms per loop
1000 loops, best of 3: 1.81 ms per loop

【讨论】:

    【解决方案3】:

    如果你只想要元素,这应该可以:

    np.intersect1d(np.around(bigx,2), np.around(x,2))
    

    如果你想要索引,试试这个:

    around_x = set(np.around(x,2))
    index_bigx = [i for i,b in enumerate(np.around(bigx,2)) if b in around_x]
    

    注意:这些都没有经过测试。

    【讨论】:

    • 感谢您的建议。我只想要索引。这比 np.where 方法快,但仍比 np.in1d 慢 1.25 倍
    猜你喜欢
    • 2018-02-22
    • 1970-01-01
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    • 2016-02-14
    • 1970-01-01
    相关资源
    最近更新 更多