查找最接近的值并在Python中返回数组的索引


问题内容

我发现了这篇文章:Python:在数组中查找元素

这是通过匹配值来返回数组的索引。

另一方面,我的想法是相似但不同。我想找到最接近目标值的值。例如,我正在寻找4.2,但是我知道数组中没有4.2,但是我想返回值4.1的索引而不是4.4。

最快的方法是什么?

我正在考虑以旧方式进行操作,就像我以前使用Matlab一样,正在使用数组A,我要从中获取索引以减去目标值并取其绝对值,然后选择最小值。像这样的东西:

[~,idx] = min(abs(A - target))

那是Matlab代码,但是我是Python的新手,所以我在想,是否有快速的方法可以在Python中完成呢?

非常感谢你的帮助!


问题答案:

这类似于使用bisect_left,但是它允许您传递目标数组

def find_closest(A, target):
    #A must be sorted
    idx = A.searchsorted(target)
    idx = np.clip(idx, 1, len(A)-1)
    left = A[idx-1]
    right = A[idx]
    idx -= target - left < right - target
    return idx

一些解释:

第一一般情况下:idx = A.searchsorted(target)返回每个的索引target,使得target之间A[index - 1]A[index]。我叫这些leftright所以我们知道left < target <= righttarget - left < right - targetTrue(或1)时的目标更接近leftFalse(或0)时的目标更接近right

现在的特殊情况:当target小于所有的元素Aidx = 0idx = np.clip(idx, 1, len(A)-1)将所有idx<1的值替换为1,因此idx=1。在这种情况下left = A[0]right = A[1]我们知道这一点target <= left <= right。为此,我们知道,target - left <= 0right - target >= 0这样target - left < right - targetTrue,除非target == left == rightidx - True = 0

还有另一种特殊情况,如果target大于的所有元素A,在这种情况下idx = A.searchsorted(target)np.clip(idx, 1, len(A)-1)将其替换len(A)len(A) - 1soidx=len(A) -1target - left < right - target最终False使idx返回len(A) -1。我会让您自己逻辑地工作。

例如:

In [163]: A = np.arange(0, 20.)

In [164]: target = np.array([-2, 100., 2., 2.4, 2.5, 2.6])

In [165]: find_closest(A, target)
Out[165]: array([ 0, 19,  2,  2,  3,  3])