【问题标题】:Nearest neighbor 1 dimensional data with a specified range具有指定范围的最近邻一维数据
【发布时间】:2013-09-16 18:56:36
【问题描述】:

我有两个嵌套列表 A 和 B:

A = [[50,140],[51,180],[54,500],......]

B = [[50.1, 170], [51,200],[55,510].....]

每个内部列表中的第一个元素从 0 到大约 1e5,第 0 个元素从大约 50 到大约 700,这些元素是未排序的。我想要做的是遍历 A[n][1] 中的每个元素并在 B[n][1] 中找到最近的元素,但是在搜索最近的邻居时,我只想在定义的区间内搜索A[n][0] 正负 0.5。

我一直在使用该功能:

def find_nearest_vector(array, value): 
   idx = np.array([np.linalg.norm(x+y) for (x,y) in array-value]).argmin()
   return array[idx]

例如,在坐标A[0][:]B[0][:]之间找到最近的邻居。但是,我需要将搜索范围限制在一个围绕值 A[0][0] 的一些小偏移的矩形内。另外,我不想重用元素 - 我想要在区间 A[n][0] +/- 0.5 内的每个值 A[n][1] 到 B[n][1] 之间的唯一双射。

我一直在尝试使用 Scipy 的 KDTree,但这会重用元素,我不知道如何限制搜索范围。实际上,我想沿特定轴在二维嵌套列表上进行一维 NNN 搜索,其中 NNN 搜索的邻域位于由每个内部列表中的第 0 个元素定义的超矩形内,加上或减去一些小偏移.

【问题讨论】:

  • 让我们看看我是否明白了你的问题:你希望find_nearest_vector() 函数被限制在某个区间(2D 区间?)。为什么不直接使用[np.linalg.norm(x+y) if array[0][0]-0.5<np.linalg.norm(x+y)<array[0][0]+0.5 else 999999 for (x,y) in array-value]
  • (也许我有一些语法问题,但我希望我能传达我的想法)
  • 不完全是,每个窗口都是由内部列表中的第 0 个元素定义的。因此,对于每次迭代,定义一个大约 A[n][0] +/- 0.5 的窗口,然后将元素 A[n][1] 匹配到 B[n] 中最近的元素。我希望这更有意义..?

标签: python algorithm numpy scipy nearest-neighbor


【解决方案1】:

我使用numpy.argsort()numpy.searchsorted()numpy.argmin() 进行搜索。

%pylab inline
import numpy as np
np.random.seed(0)
A = np.random.rand(5, 2)
B = np.random.rand(100, 2)
xaxis_range = 0.02
order = np.argsort(B[:, 0])
bx = B[order, 0]
sidx = np.searchsorted(bx, A[:, 0] - xaxis_range, side="right")
eidx = np.searchsorted(bx, A[:, 0] + xaxis_range, side="left")
result = []
for s, e, ay in zip(sidx, eidx, A[:, 1]):
    section = order[s:e]
    by = B[section, 1]
    idx = np.argmin(np.abs(ay-by))
    result.append(B[section[idx]])
result = np.array(result)

我将结果绘制如下:

plot(A[:, 0], A[:, 1], "o")
plot(B[:, 0], B[:, 1], ".")
plot(result[:, 0], result[:, 1], "x")

输出:

【讨论】:

  • 我有一个问题 - 当 A 和 B 的列表长度变大时,我不断收到错误 - ValueError: attempt to get argmax/argmin of an empty sequence - 你知道这是什么原因吗?
  • 这表示A[:,0] - 0.5 ~ A[:,0] + 0.5之间没有B,这会导致s == e,而sectionby是空。
【解决方案2】:

我对您的问题的理解是,您正试图在另一组点中为每个 A[n][1] 找到最接近的元素(B[i][1] 仅限于如果 A[n][0]B[i][0] 的 +/- 0.5 范围内的点)。

我不熟悉 numpy 或 scipy,我确信他们的算法有更好的方法。

话虽如此,这是我在O(a*b*log(a*b)) 时间的幼稚实现。

def main(a,b):
    for a_bound,a_val in a:
        dist_to_valid_b_points = {abs(a_val-b_val):(b_bound,b_val) for b_bound,b_val in b if are_within_bounds(a_bound,b_bound)}
        print get_closest_point((a_bound, a_val),dist_to_valid_b_points)

def are_within_bounds(a_bound, b_bound):
    return abs(b_bound-a_bound) < 0.5

def get_closest_point(a_point, point_dict):
    return (a_point, None if not point_dict else point_dict[min(point_dict, key=point_dict.get)])

main([[50,140],[51,180],[54,500]],[[50.1, 170], [51,200],[55,510]]) 产生以下输出:

((50, 140), (50.1, 170))
((51, 180), (51, 200))
((54, 500), None)

【讨论】:

  • 这似乎有效,非常感谢 - 在我接受答案之前,我将不得不花一些时间检查一下。但是,我有一个问题 - 输出中的第三个元素是 ((54, 500), None) 而不是 ((54, 500), (55,510))..?
  • 54和55之间的距离大于0.5,所以(55,510)are_within_bounds排除在外。
猜你喜欢
  • 2011-08-10
  • 1970-01-01
  • 2018-08-17
  • 1970-01-01
  • 2015-11-16
  • 2018-02-26
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多