我有这样的矢量:
intervals = [6, 7, 8, 9, 10, 11] #always regular
我想检查一个值是哪个区间索引。例如:8.5
所在的区间索引为3
。
#Interval : index
6 -> 7 : 1
7 -> 8 : 2
8 -> 9 : 3
9 -> 10 : 4
10 -> 11 : 5
所以我制作了这段代码:
from numpy import *
N = 8000
data = random.random(N)
step_number = 50
max_value = max(data)
min_value = min(data)
step_length = (max_value - min_value)/step_number
intervals = arange(min_value + step_length, max_value + step_length, step_length )
for x in data:
for index in range(len(intervals)):
if x < intervals[index]:
print("That's the index", index)
break
这段代码正在运行,但它太慢了,我想我在这些循环中浪费时间。有没有办法更快地检查?也许使用一些numpy特殊功能来检查这个......
答案 0 :(得分:6)
根据您希望如何处理端点,有bisect.bisect_left
和bisect.bisect_right
:
>>> import bisect
>>> intervals = [6, 7, 8, 9, 10, 11]
>>> for n in (6, 6.1, 6.2, 6.5, 6.8, 7):
... print bisect.bisect_left(intervals, n)
...
0
1
1
1
1
1
>>> for n in (6, 6.1, 6.2, 6.5, 6.8, 7):
... print bisect.bisect_right(intervals, n)
...
1
1
1
1
1
2
Numpy使用searchsorted
方法实现相同的功能。
>>> import numpy as np
>>> np.searchsorted(intervals, (6, 6.1, 6.2, 6.5, 6.8, 7), side='left')
array([0, 1, 1, 1, 1, 1])
>>> np.searchsorted(intervals, (6, 6.1, 6.2, 6.5, 6.8, 7), side='right')
array([1, 1, 1, 1, 1, 2])
当然,如果您的间隔间隔相等,您可以这样做:
>>> for n in (6, 6.1, 6.2, 6.5, 6.8, 7):
... iwidth = intervals[1] - intervals[0]
... print np.ceil((n - intervals[0]) / iwidth)
...
0.0
1.0
1.0
1.0
1.0
1.0
答案 1 :(得分:2)
正如其他人所提到的,如果您的间隔不规则,请使用二等分搜索(例如np.searchsorted
和/或np.digitize
)。
但是,在您声明您将始终有规律间隔的特定情况下,您也可以执行类似的操作:
import numpy as np
intervals = [6, 7, 8, 9, 10, 11]
vals = np.array([8.5, 6.2, 9.8])
dx = intervals[1] - intervals[0]
x0 = intervals[0]
i = np.ceil((vals - x0) / dx).astype(int)
或者,以您的示例代码为基础:
import numpy as np
N = 8000
num_intervals = 50
data = np.random.random(N)
intervals = np.linspace(data.min(), data.max(), num_intervals)
x0 = intervals[0]
dx = intervals[1] - intervals[0]
i = np.ceil((data - x0) / dx).astype(int)
这比大型数组的二进制搜索要快得多。
答案 2 :(得分:1)
只要您的列表已排序,您就可以使用bisect库来获取插入索引。
index = bisect.bisect_left(intervals, 8.5)
答案 3 :(得分:0)
只使用numpy:
import numpy as np
intervals = np.array([6, 7, 8, 9, 10, 11])
val = (intervals > 8.5)
print val.argmax()
答案 4 :(得分:0)
我会选择一个功能:
def f_idx(f_list, number):
for idx,item in enumerate(f_list):
if item>number:
return idx
return len(f_list)
在一个班轮中:
result = [idx for idx,value in enumerate(intervals) if value>number][0] if intervals[-1]>number else len(intervals)
答案 5 :(得分:0)
使用numpy.digitize
:
http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.digitize.html#numpy-digitize
>>> import numpy as np
>>> intervals = [6, 7, 8, 9, 10, 11]
>>> data = [3.5, 6.3, 9.4, 11.5, 8.5]
>>> np.digitize(data, bins=interval)
array([0, 1, 4, 6, 3])
0
下溢,len(intervals)
溢出