【问题标题】:Finding the nearest value and return the index of array in Python在 Python 中查找最接近的值并返回数组的索引
【发布时间】:2012-02-13 10:18:32
【问题描述】:

我发现了这个帖子:Python: finding an element in an array

它是关于通过匹配值返回数组的索引。

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

最快的方法是什么?

我正在考虑用旧的方式来做这件事,就像我以前用 Matlab 做的那样,它使用数组 A,我想从中获取索引减去目标值并取其绝对值,然后选择分钟。像这样的东西:-

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

这是 Matlab 代码,但我是 Python 新手,所以我在想,有没有一种在 Python 中快速的方法?

非常感谢您的帮助!

【问题讨论】:

标签: python numpy python-3.x


【解决方案1】:

这类似于使用 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 &lt; target &lt;= right。当目标更接近lefttarget - left &lt; right - targetTrue(或1),当目标更接近rightFalse(或0)。

现在是特殊情况:当target 小于Aidx = 0 的所有元素时。 idx = np.clip(idx, 1, len(A)-1)idx idx=1。在这种情况下left = A[0]right = A[1],我们知道target &lt;= left &lt;= right。因此我们知道target - left &lt;= 0right - target &gt;= 0 所以target - left &lt; right - targetTrue 除非target == left == rightidx - True = 0

如果target大于A的所有元素还有另一种特殊情况,在这种情况下idx = A.searchsorted(target)np.clip(idx, 1, len(A)-1) len(A)替换len(A) - 1所以idx=len(A) -1target - left &lt; 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])

【讨论】:

  • 非常感谢@Bago!我正在尝试理解代码,但idx -= target - left &lt; right - target 部分存在问题。我是 Python 新手,所以我首先测试了 target - left &lt; right - target,它们返回了 TrueFalse 的范围。我使用 idx 减去结果,得到一个稍微失真的数组。例如,原始索引 0 变为 -1。我在这里错过了什么吗?
【解决方案2】:

嗯,2 年多过去了,实际上我从这个 URL 中找到了一个非常简单的实现:Find nearest value in numpy array

实现是:

def getnearpos(array,value):
    idx = (np.abs(array-value)).argmin()
    return idx   

干杯!!

【讨论】:

    【解决方案3】:

    测试并计时了两种解决方案:

    idx = np.searchsorted(sw, sCut)
    

    idx = np.argmin(np.abs(sw - sCut))
    

    用于以耗时的方法进行计算。 第二个解决方案的计算时间为 113 秒,第一个解决方案的计算时间为 132 秒

    【讨论】:

    • 请注意,这些返回不同的结果。 np.argmin(np.abs(np.array([1, 2, 3, 4]) - 2.1)) 返回 1,其中 np.searchsorted([1, 2, 3, 4], 2.1) 返回 2...np.searchsorted 返回插入位置以保留顺序,因此它返回目标后第一个值的索引,可能不是最近的值。使用最小化abs(value-target) 的任何方法实际上是在找到可能高于或低于目标的最接近的值。根据您的需要,两者都可能合适,但它们并不等效。
    【解决方案4】:
    def finder(myList, target)
        diff = ''
        index = None
        for i,num in enumerate(myList):
            if abs(target - num) < diff:
                diff = abs(target - num)
                index = i
        return index
    

    希望对你有帮助

    编辑

    如果您想要单线,那么您可能会更喜欢这个:

    min(L, key=lambda x: abs(target-x))
    

    【讨论】:

      【解决方案5】:

      可能的解决方案:

      >>> a = [1.0, 3.2, -2.5, -3.1]
      >>> i = -1.5
      >>> diff = [(abs(i - x),idx) for (idx,x) in enumerate(a)]
      >>> diff
      [(2.5, 0), (4.7, 1), (1.0, 2), (1.6, 3)]
      >>> diff.sort()
      >>> diff
      [(1.0, 2), (1.6, 3), (2.5, 0), (4.7, 1)]
      

      您将在 diff[0][1] 中获得最接近值的索引

      【讨论】:

        【解决方案6】:

        对应的 Numpy 代码几乎相同,只是你使用numpy.argmin 查找最小索引。

        idx = numpy.argmin(numpy.abs(A - target))
        

        【讨论】:

        • 如果输入数组按排序顺序,numpy.searchsorted 也很方便(而且效率更高)。
        • OP 没有具体说明,但我想我会指出,如果 A = [4.1, 4.4, 5, 4.1]target = 4.2。此代码将仅返回 idx = 0 而不是 idx = [0, 3]。是否唯一的方法是循环返回 A,将每个值与 idx = 0 的值进行比较,以确定是否还有其他值?
        • @sgallen:贴出的 Matlab 代码 OP 给出了idx = 1(Matlab 索引是从 1 开始的),所以我猜其他的都不需要。
        • 正如@JoeKington 已经提到的那样,searchsorted 如果对 A 进行排序会更快,但它也可以将目标数组作为参数,因此如果您需要重复此操作超过一个目标。如果这对你有用,请告诉我,我会写下来作为答案。
        • 老实说,我使用这个函数来搜索排序数组。如果你能指导我,我将非常感激,@Bago。太感谢了!你们真的很有帮助。
        猜你喜欢
        • 2012-02-13
        • 2019-12-14
        • 2016-07-19
        • 1970-01-01
        • 2018-06-05
        • 2021-10-15
        • 1970-01-01
        • 1970-01-01
        • 2013-03-29
        相关资源
        最近更新 更多