Python 检测元素是否在成对的间隔限制内
我将数组设置为:Python 检测元素是否在成对的间隔限制内,python,performance,pandas,numpy,Python,Performance,Pandas,Numpy,我将数组设置为: A = np.array([1, 6, 4, 4, 5, 6]) B = np.array([5, 40, 4, 6, 54,7]) #same size as A but every element of B is greater than corresponding element of A C = np.array([6, 3]) 我想找到A和B的所有行,这样C>=A和C,特别是如果A和B非常大,通过C循环的开销几乎可以忽略。然而,如果C很长,但A和B很短,那么您需要
A = np.array([1, 6, 4, 4, 5, 6])
B = np.array([5, 40, 4, 6, 54,7]) #same size as A but every element of B is greater than corresponding element of A
C = np.array([6, 3])
我想找到A和B的所有行,这样C>=A和C,特别是如果A和B非常大,通过C循环的开销几乎可以忽略。然而,如果C很长,但A和B很短,那么您需要考虑一种广播方法,因为这样python循环将引入大量开销 显式循环的simple方法 广播方式
然而,广播方法将创建大尺寸=A.size*C.size中间数组,因此如果A、B和C很大,这将需要大量内存。特别是如果A和B非常大,通过C循环的开销几乎可以忽略。然而,如果C很长,但A和B很短,那么您需要考虑一种广播方法,因为这样python循环将引入大量开销 显式循环的simple方法 广播方式 然而,广播方法将创建大尺寸=A.size*C.size中间阵列,因此如果A、B和C很大,则需要大量内存。预期解决方案 看起来A和B是上下边界,有点像区间边界,我们的任务是检测C中的任何元素是否在这些区间中。对于这样的边界相关问题,通常可以与其可选的side参数一起使用,该参数接受left和right作为输入参数。这个函数让我们获得第一个索引,其中每个要搜索的元素都存在于提供给side参数的那一侧。因此,我们需要寻找索引,其中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)
远景方案
看起来A和B是上下边界,有点像区间边界,我们的任务是检测C中的任何元素是否在这些区间中。对于这样的边界相关问题,通常可以与其可选的side参数一起使用,该参数接受left和right作为输入参数。这个函数让我们获得第一个索引,其中每个要搜索的元素都存在于提供给side参数的那一侧。因此,我们需要寻找索引,其中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)
为了澄清-你想得到A和B的所有元素,这样就有一个j满足A[i],你不需要找到C的最大值,然后与A和C的最小值进行比较,再与B进行比较。为什么第一个例子中的1不是要澄清-你想得到A和B的所有元素,这样就有一个j满足A[i]难道你不需要找到C的最大值并与A和C的最小值进行比较以与B进行比较吗?为什么在第一种情况下1不是1?这将进一步缩短解决方案的时间,因为我的C已排序。这将进一步缩短解决方案的时间,因为我的C已排序。
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')
# 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