代码之家  ›  专栏  ›  技术社区  ›  Demetri Pananos

在数组中查找“close”的元素

  •  1
  • Demetri Pananos  · 技术社区  · 6 年前

    我有一个一维排序的数组,希望找到所有差异不大于5的元素对。

    一个幼稚的方法是做n^2比较

    diffs = np.tile(x, (x.size,1) ) - x[:, np.newaxis]
    D = np.logical_and(diffs>0, diffs<5)
    indicies = np.argwhere(D)
    

    请注意,我的示例的输出是 x .如果我想要 X 符合标准,我可以 x[indicies] . 这适用于较小的数组,但不适用于我使用的大小的数组。

    我的一个想法是找出连续元素之间的差距大于5。我将把数组分成两部分,并比较每个部分中的所有元素。

    这是找到满足我标准的元素的更有效的方法吗?我该怎么写呢?

    下面是一个小例子:

    x = np.array([ 9, 12, 
               21, 
               36, 39, 44, 46, 47, 
               58, 
               64, 65,])
    

    结果应该是

    array([[ 0,  1],
           [ 3,  4],
           [ 5,  6],
           [ 5,  7],
           [ 6,  7],
           [ 9, 10]], dtype=int64)
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Paul Panzer    6 年前

    下面是一个迭代偏移量的解决方案,同时缩小候选集,直到没有剩余值为止:

    import numpy as np
    
    def f_pp(A, maxgap):
        d0 = np.diff(A)
        d = d0.copy()
        IDX = []
        k = 1
        idx, = np.where(d <= maxgap)
        vidx = idx[d[idx] > 0]
        while vidx.size:
            IDX.append(vidx[:, None] + (0, k))
            if idx[-1] + k + 1 == A.size:
                idx = idx[:-1]
            d[idx] = d[idx] + d0[idx+k]
            k += 1
            idx = idx[d[idx] <= maxgap]
            vidx = idx[d[idx] > 0]
        return np.concatenate(IDX, axis=0)
    
    data = np.cumsum(np.random.exponential(size=10000)).repeat(np.random.randint(1, 20, (10000,)))
    
    pairs = f_pp(data, 1)
    #pairs = set(map(tuple, pairs))
    
    from timeit import timeit
    kwds = dict(globals=globals(), number=100)
    print(data.size, 'points', pairs.shape[0], 'close pairs')
    print('pp', timeit("f_pp(data, 1)", **kwds)*10, 'ms')
    

    样本运行:

    99963 points 1020651 close pairs
    pp 43.00256529124454 ms
    
        2
  •  0
  •   anishtain4    6 年前

    对数组进行切片是一种非常有效的方法。由于对数据进行了排序,您可以计算差异并将其拆分:

    d=np.diff(x)
    ind=np.where(d>5)[0]
    pieces=np.split(x,ind)
    

    在这里 pieces 是一个列表,在该列表中,您可以在循环中对每个元素使用自己的代码。

    最好的算法高度依赖于我不知道的数据的性质。例如,另一种可能是编写嵌套循环:

    pairs=[]
    for i in range(x.size):
        j=i+1
        while x[j]-x[i]<=5 and j<x.size:
            pairs.append([i,j])
            j+=1
    

    如果你想让它更聪明,你可以通过编辑外循环来在 j 撞到一个缺口。