向量化方法,用于提取包含另一个数组元素的端点数组的行

时间:2019-07-20 04:31:40

标签: python arrays performance numpy vectorization

标题怎么说。我正在寻找一种快速且pythonic的方法来提取端点数组A的行,该端点数组包含另一个数组v

的元素

我想要实现的一个简单示例如下:

输入:

A = [[ 4  9]
     [15 19]
     [20 28]
     [31 37]
     [43 43]]    
v =  [ 0  1  2  3 11 12 13 14 26 29 30 31 43]

因为A是结束品脱数组,这意味着在每一行中,第一个元素和第二个元素代表间隔的开始和结束。由于仅[20 28][31 37][43 43]的间隔包含v中的元素(在这种情况下,26,31 and 43包含在端点数组{{1 }}),所需的输出是:

A

以下是生成实际输入数组的代码:

[[20 28]
 [31 37]
 [43 43]]

提前谢谢


编辑:在说明中添加了更多详细信息

4 个答案:

答案 0 :(得分:3)

方法1

我们可以使用np.searchsorted来获取v值相对于每一行的开始和结束元素的左右位置索引,并寻找不匹配的值,这将表明特定的行在这些范围内至少有一个元素。因此,我们可以简单地-

A[np.searchsorted(v,A[:,0],'left')!=np.searchsorted(v,A[:,1],'right')]

方法2

另一种方法是使用位于左侧的索引来索引v,然后查看它们是否小于右侧端点。因此,它将是-

idx = np.searchsorted(v,A[:,0],'left')
out = A[(idx<len(v)) & (v[idx.clip(max=len(v)-1)]<=A[:,1])]

请注意,这假设v被排序并以数组形式输入。如果v尚未排序,则需要对其进行排序,然后再输入。

在我的大数据集上计时-

In [65]: %timeit A[np.searchsorted(v,A[:,0],'left')!=np.searchsorted(v,A[:,1],'right')]
2 ms ± 10.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [66]: %%timeit
    ...: idx = np.searchsorted(v,A[:,0],'left')
    ...: out = A[(idx<len(v)) & (v[idx.clip(max=len(v)-1)]<=A[:,1])]
1.32 ms ± 7.87 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

答案 1 :(得分:1)

沿第三维进行比较

import numpy as np
a = np.array([[ 4,  9],
              [15, 19],
              [20, 28],
              [31, 37],
              [43, 43]])    
v =  np.array([ 0,  1,  2,  3, 11, 12, 13, 14, 26, 29, 30, 31, 43])
between = np.logical_and(v >= a[:,0,None], v <= a[:,1,None])
print(a[between.any(-1)])

>>>
[[20 28]
 [31 37]
 [43 43]]
>>> 

答案 2 :(得分:1)

我不认为这完全是Python语言,但至少是O(n)。

def find_bounding_intervals(A, v):
    rows = []
    i = 0
    for row in A:
        while all(v[i] < row):
            i += 1
        if row[0] <= v[i] <= row[1]:
            rows.append(row)
    return np.array(rows)

A = np.array([[ 4,  9],
              [15, 19],
              [20, 28],
              [31, 37],
              [43, 43]])
v =  np.array([ 0,  1,  2,  3, 11, 12, 13, 14, 26, 29, 30, 31, 43])
print(find_bounding_intervals(A, v))

我的低端笔记本电脑在约0.28秒内为您的问题中定义的更大数据提供了解决方案。

答案 3 :(得分:1)

n

尽管从技术上来说,此实现不是矢量化函数,但实际上,它在ssh root@$HWNODEIP "while ! test -e /root/kickstart-DONE; do sleep 3; done; echo KICKSTART IS DONE...\!" 的几乎所有大小中都是最快的。

我应该明确指出该算法来自@brentertainer