标题怎么说。我正在寻找一种快速且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]]
提前谢谢
编辑:在说明中添加了更多详细信息
答案 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