我有一个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)
答案 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
遇到间隙时以跳跃的方式编辑外环。