Python 快速查找数组中最接近某个值的索引

Python 快速查找数组中最接近某个值的索引,python,performance,indexing,numpy,Python,Performance,Indexing,Numpy,我有一个值数组,t,它总是以递增的顺序排列(但不总是等距排列)。我还有一个值,x。我需要在t中找到索引,使得t[index]最接近x。函数必须为xt.max()返回最大索引(或-1) 为此,我编写了两个函数。第一个,f1,在这个简单的计时测试中要快得多。但我喜欢第二行只是一行。此计算将在大型阵列上进行,可能每秒多次 有人能想出一些其他的功能,与第一个功能的时间相当,但是代码看起来更干净吗?比第一个快一点的怎么样(速度是最重要的) 谢谢 代码: 将numpy导入为np 导入时间信息 t=np.ar

我有一个值数组,t,它总是以递增的顺序排列(但不总是等距排列)。我还有一个值,x。我需要在t中找到索引,使得t[index]最接近x。函数必须为xt.max()返回最大索引(或-1)

为此,我编写了两个函数。第一个,f1,在这个简单的计时测试中要快得多。但我喜欢第二行只是一行。此计算将在大型阵列上进行,可能每秒多次

有人能想出一些其他的功能,与第一个功能的时间相当,但是代码看起来更干净吗?比第一个快一点的怎么样(速度是最重要的)

谢谢

代码:

将numpy导入为np
导入时间信息
t=np.arange(10100000)#不总是一致的,但顺序是递增的
x=np.random.uniform(10100000)#在t中找到一些值
def f1(t,x):
ind=np.searchsorted(t,x)#获取索引以保持顺序
ind=最小值(len(t)-1,ind)#如果x>max(t)
ind=最大值(1,ind)#如果x
使用搜索排序:

t = np.arange(10,100000)         # Not always uniform, but in increasing order
x = np.random.uniform(10,100000)

print t.searchsorted(x)
编辑:

啊,是的,我知道你在f1就是这么做的。也许下面的f3比f1更容易阅读

def f3(t, x):
    ind = t.searchsorted(x)
    if ind == len(t):
        return ind - 1 # x > max(t)
    elif ind == 0:
        return 0
    before = ind-1
    if x-t[before] < t[ind]-x:
        ind -= 1
    return ind
def f3(t,x):
ind=t.x(x)
如果ind==len(t):
返回ind-1#x>max(t)
elif ind==0:
返回0
之前=ind-1
如果x-t[before]
np.searchsorted
是二进制搜索(每次将数组一分为二)。因此,您必须以一种方式实现它,它返回小于x的最后一个值,而不是返回零

看看这个算法(来自):

def二进制搜索(a,x):
lo=0
hi=len(a)
当lox:
高=中
其他:
中途返回
如果lo>0,则返回lo-1,否则返回0
刚刚替换了最后一行(was
return-1
)。也改变了论点

由于循环是用Python编写的,因此可能比第一个循环慢。。。(未进行基准测试)

这似乎要快得多(对我来说,Python 3.2-win32,numpy 1.6.0):


输出:

[   10    11    12 ..., 99997 99998 99999]
37854.22200356027
37844
37844
37844
37854
37854
37854
f1 0.332725
f2 1.387974
f3 0.085864

由于数组已排序,请尝试二进制搜索。看看这个问题的答案:我刚离开工作,但想稍后再看。我认为在测试了xmax(t)之后,可以通过短路来改进第一个函数,但我还没有机会测试它。这只是给出了数字插入位置的索引,不一定是最接近的索引。这就是为什么他的f1函数需要额外的步骤。啊,是的,我没有看到f1中的搜索排序。对不起,是的,快多了。然而,它确实需要稍微调整,以考虑特殊情况,其中xt.maxIt如果间隙较大,也不能正常工作:
f3([100200],199)
表示
0
,尽管
200
100
更接近
199
。看见
def binary_search(a, x):
    lo=0
    hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        midval = a[mid]
        if midval < x:
            lo = mid+1
        elif midval > x: 
            hi = mid
        else:
            return mid
    return lo-1 if lo > 0 else 0
from bisect import bisect_left
def f3(t, x):
    i = bisect_left(t, x)
    if t[i] - x > 0.5:
        i-=1
    return i
[   10    11    12 ..., 99997 99998 99999]
37854.22200356027
37844
37844
37844
37854
37854
37854
f1 0.332725
f2 1.387974
f3 0.085864