在数组中找到那些" close"

时间:2018-06-12 19:26:37

标签: numpy

我有一个1维排序数组,想找到差别不大于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 个答案:

答案 0 :(得分:1)

这是一个解决偏移量的解决方案,同时缩小候选集合,直到没有剩余:

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

答案 1 :(得分:0)

您对切割数组的想法是一种非常有效的方法。由于您的数据已经排序,您只需计算差异并将其拆分:

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遇到间隙时以跳跃的方式编辑外环。