【问题标题】:Detect if elements are within pairs of interval limits检测元素是否在成对的区间范围内
【发布时间】:2017-09-08 23:21:33
【问题描述】:

我有数组:

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])

我想找到AB 的所有行,例如C>=AC<=BA and B 表单对的相同行,因此必须一起选择。

所以,输出数组将是:

For C[0] = 6
Aout = [6, 4, 5, 6]
Bout = [40, 6, 54, 7]

ForC[1] = 3
Aout = [1]
Bout = [5]

因此,最终输出如下所示:

Aout = [1, 6, 4, 5, 6]
Bout = [5, 40, 6, 54, 7]

目前我正在考虑使用numpy.where 并循环遍历C 的每个元素,但考虑到我的尺寸非常大A, B and C 这似乎是一个非常低效的过程。

如果使用 pandas 有更简单的方法,我会更喜欢。

【问题讨论】:

  • 澄清一下-您想获取AB 的所有元素,以便有一个满足A[i] <= C[j] <= B[i]j?我不确定你写“行”时的意思。
  • 您不只需要找到Cmax 并与ACmin 进行比较即可与B 进行比较。为什么1 在您的第一种情况下不是1 <= 6

标签: python performance pandas numpy


【解决方案1】:

特别是如果您有非常大的AB,循环通过C 的开销几乎可以忽略不计。但是,如果C 很长,而AB 很短,那么您需要考虑广播方法,因为这样python 循环将引入大量开销。

显式循环的简单方法

mask = np.zeros(A.shape, dtype=bool)
for item in C:
    mask |= (A<=item) & (B>=item)

A[mask], B[mask]  # select the valid elements

广播方法

mask= ((A[:, None]<=C) & (B[:, None]>=C)).max(axis=1)

A[mask], B[mask]  # select the valid elements

然而,广播方法会创建大的 (size= A.size * C.size) 中间数组,因此如果 AB C 很大,这将需要大量内存。

【讨论】:

    【解决方案2】:

    前瞻性解决方案

    似乎AB 充当上下边界,有点像区间边界,我们的任务是检测C 中的任何元素是否在每个区间中。对于此类与边界相关的问题,numpy.searchsorted 通常可以与其可选的side 参数一起使用,该参数接受leftright 作为输入参数。这个函数让我们获得第一个索引,其中每个要搜索的元素都存在于提供给side 参数的一侧。因此,我们需要寻找那些leftright 边匹配索引分别出现在AB 元素对中的索引。这些相同的情况表明元素位于边界限制的同一侧,即不在该对的边界限制内。因此,我们需要寻找不平等作为最终衡量标准。

    因此,实现将是 -

    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,我们需要将其掩码到 AB 上以获得最终输出: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
    

    【讨论】:

    • 这将进一步缩短您的解决方案的时间,因为我的 C 已经排序。
    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 2021-03-30
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    • 1970-01-01
    • 2017-02-28
    • 2012-11-11
    相关资源
    最近更新 更多