首页 文章

查找最接近值的numpy数组的所有索引

提问于
浏览
1

在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 回答

  • 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
    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
    
  • 1

    我想你在这里有两个选择 . 一种是对形状做出一些假设,并寻找 seqval 之间差异的过零点(如@ColonelFazackerley中所做的@ColonelFazackerley) . 另一个是要说明你想要将相对容差考虑到足够接近的值 .

    在后一种情况下,您可以使用 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 ),你会得到接近交叉点的多个值,将它设置得太低而你没有得到任何值 .

  • 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
    

相关问题