前瞻性解决方案
似乎A 和B 充当上下边界,有点像区间边界,我们的任务是检测C 中的任何元素是否在每个区间中。对于此类与边界相关的问题,numpy.searchsorted 通常可以与其可选的side 参数一起使用,该参数接受left 和right 作为输入参数。这个函数让我们获得第一个索引,其中每个要搜索的元素都存在于提供给side 参数的一侧。因此,我们需要寻找那些left 和right 边匹配索引分别出现在A 和B 元素对中的索引。这些相同的情况表明元素位于边界限制的同一侧,即不在该对的边界限制内。因此,我们需要寻找不平等作为最终衡量标准。
因此,实现将是 -
def ingrps_searchsorted(A, B, C):
# searchsorted needs the first input to be sorted
S = np.sort(C)
# Use searchsorted and look for
return np.searchsorted(S, A, 'left') != np.searchsorted(S, B, 'right')
这将为我们提供一个掩码,例如 m,我们需要将其掩码到 A 和 B 上以获得最终输出:A[m] 和 B[m]。
运行时测试
其他方法 -
# MSeifert's soln1
def ingrps_loop(A, B, C):
mask = np.zeros(A.shape, dtype=bool)
for item in C:
mask |= (A<=item) & (B>=item)
return mask
# MSeifert's soln2
def ingrps_broadcasting(A, B, C):
return ((A[:, None]<=C) & (B[:, None]>=C)).max(axis=1)
掩码创建的时间和验证:
In [342]: # Setup inputs so that around 20% matches exist
...: A = np.random.randint(0,50,(10000))
...: B = A + np.random.randint(0,50,(10000))
...: C = np.random.randint(0,100,(10000))
...:
In [343]: np.allclose(ingrps_loop(A, B, C), ingrps_broadcasting(A, B, C))
Out[343]: True
In [344]: np.allclose(ingrps_loop(A, B, C), ingrps_searchsorted(A, B, C))
Out[344]: True
In [345]: %timeit ingrps_loop(A, B, C)
...: %timeit ingrps_broadcasting(A, B, C)
...: %timeit ingrps_searchsorted(A, B, C)
...:
10 loops, best of 3: 101 ms per loop
10 loops, best of 3: 102 ms per loop
1000 loops, best of 3: 1.79 ms per loop
In [346]: # Setup inputs so that around 20% matches exist
...: A = np.random.randint(0,50,(100000))
...: B = A + np.random.randint(0,50,(100000))
...: C = np.random.randint(0,100,(100000))
...:
In [347]: %timeit ingrps_loop(A, B, C)
...: %timeit ingrps_searchsorted(A, B, C)
...:
1 loops, best of 3: 8.18 s per loop
10 loops, best of 3: 26.5 ms per loop
In [348]: 8180/26.5 # Speedup number with proposed solution over loopy one
Out[348]: 308.6792452830189