查找最接近值

时间:2018-02-21 08:16:05

标签: python numpy search

在numpy数组中,需要最接近给定常量的所有值的索引。 背景是数字信号处理。该阵列保持滤波器(np.abs(np.fft.rfft(h)))的幅度函数,并搜索某些频率(=索引),其幅度为例如0.5或在另一种情况下0。 大多数情况下,有问题的值并未完全包含在序列中。闭合值的索引应该在此中找到。

到目前为止,我想出了以下方法,其中我看到了序列和常量之间差异的符号变化。然而,这仅适用于在所讨论的点处单调增加或减少的序列。它有时也会减1。

def findvalue(seq, value):
    diffseq = seq - value
    signseq = np.sign(diffseq)
    signseq[signseq == 0] = 1
    return np.where(np.diff(signseq))[0]

我想知道是否有更好的解决方案。它仅适用于1D实数浮点数组,在我的情况下,计算效率的要求并不高。

作为数值示例,以下代码应返回[8, 41]。为了简单起见,我用半波替换了滤波器幅度响应。

f=np.sin(np.linspace(0, np.pi))
findvalue(f, 0.5)

我发现的类似问题如下,但它们只返回第一个或第二个索引:
Find the second closest index to value
Find nearest value in numpy array

4 个答案:

答案 0 :(得分:1)

以下函数将返回一个小数索引,显示大约何时超过该值:

def FindValueIndex(seq, val):
    r = np.where(np.diff(np.sign(seq - val)) != 0)
    idx = r + (val - seq[r]) / (seq[r + np.ones_like(r)] - seq[r])
    idx = np.append(idx, np.where(seq == val))
    idx = np.sort(idx)
    return idx

逻辑:查找seq-val符号的变化。取转换和插值下方和上方的一个索引值。添加到此索引,其中值实际上等于该值。

如果你想要一个整数索引,只需使用np.round。您也可以选择np.floor或np.ceil将索引四舍五入为您的首选项。

def FindValueIndex(seq, val):
    r = np.where(np.diff(np.sign(seq - val)) != 0)
    idx = r + (val - seq[r]) / (seq[r + np.ones_like(r)] - seq[r])
    idx = np.append(idx, np.where(seq == val))
    idx = np.sort(idx)
    return np.round(idx)

答案 1 :(得分:1)

def findvalue(seq, value):
    diffseq = seq - value
    signseq = np.sign(diffseq)
    zero_crossings = signseq[0:-2] != signseq[1:-1]
    indices = np.where(zero_crossings)[0]
    for i, v in enumerate(indices):
        if abs(seq[v + 1] - value) < abs(seq[v] - value):
            indices[i] = v + 1
    return indices

更多解释

def print_vec(v):
    for i, f in enumerate(v):
        print("[{}]{:.2f} ".format(i,f), end='')
    print('')

def findvalue_loud(seq, value):
    diffseq = seq - value
    signseq = np.sign(diffseq)
    print_vec(signseq)
    zero_crossings = signseq[0:-2] != signseq[1:-1]
    print(zero_crossings)

    indices = np.where(zero_crossings)[0]
    # indices contains the index in the original vector
    # just before the seq crosses the value [8 40]
    # this may be good enough for you
    print(indices)

    for i, v in enumerate(indices):
        if abs(seq[v + 1] - value) < abs(seq[v] - value):
            indices[i] = v + 1
    # now indices contains the closest [8 41]
    print(indices)
    return indices

答案 2 :(得分:1)

我认为你有两个选择。一种是对形状做出一些假设,并寻找seqval之间差异的过零点(@ColonelFazackerley中的their answer)。另一个是要说明你想要考虑哪个相对容差值足够接近。

在后一种情况下,您可以使用numpy.isclose

import numpy as np

def findvalue(seq, val, rtol=0.05):    # value that works for your example
    return np.where(np.isclose(seq, val, rtol=rtol))[0]

示例:

x = np.sin(np.linspace(0, np.pi))
print(findvalue(x, 0.5))
# array([ 8, 41])

这样做的缺点在于它取决于rtol的值。将它设置得太大(本例中为0.1),你会得到靠近交叉点的多个值,将它设置得太低而且你没有得到任何值。

答案 3 :(得分:0)

这可能远不是最好的方法(我还在学习numpy),但我希望它能帮助你找到一个。

min_distance = np.abs(your_array - your_constant).min()
# These two tuples contain number closest to your constant from each side.
np.where(bar == val - min_distance)  # Closest, < your_constant
np.where(bar == val + min_distance)  # Closest, > your_constant