在大PandasIntervalindex中寻找匹配区间

2024-10-01 11:36:57 发布

您现在位置:Python中文网/ 问答频道 /正文

在0.20中有一个有趣的API,名为Intervalindexnew,它允许您创建间隔索引。在

给出一些样本数据:

data = [(893.1516130000001, 903.9187099999999),
 (882.384516, 893.1516130000001),
 (817.781935, 828.549032)]

您可以这样创建索引:

^{pr2}$

Intervals的一个有趣的特性是,可以使用in执行间隔检查:

print(y[-1])
Interval(817.78193499999998, 828.54903200000001, closed='right')

print(820 in y[-1])
True

print(1000 in y[-1])
False

我想知道如何将此操作应用于整个索引。例如,给定某个数字900,如何检索这个数字所适合的区间的布尔掩码?在

我能想到:

m = [900 in y for y in idx]
print(m)
[True, False, False]

有更好的方法吗?在


Tags: 数据inapifalsetruedata间隔数字
3条回答

您可以使用map

idx.map(lambda x: 900 in x)
#Index([True, False, False], dtype='object')

时间安排:

^{pr2}$

很明显,理解是最快的,但是内置的map不会落后太多。在

当我们引入更多的数据,精确地说,是更多数据的10万倍时,结果仍然是:

%timeit [900 in y for y in idx]
#10 loops, best of 3: 26.8 ms per loop

%timeit idx.map(lambda x: 900 in x)
#10 loops, best of 3: 30 ms per loop

%timeit map(lambda x: 900 in x, idx)
#10 loops, best of 3: 29.5 ms per loop

正如我们所见,内置的map非常接近.map()所以-让我们看看10倍以上的数据会发生什么:

%timeit [900 in y for y in idx]
#1 loop, best of 3: 270 ms per loop

%timeit idx.map(lambda x: 900 in x)
#1 loop, best of 3: 299 ms per loop

%timeit map(lambda x: 900 in x, idx)
#1 loop, best of 3: 291 ms per loop

结论:

理解是赢家,但在大量的数据上并不明显。在

如果你在寻找速度,你可以使用idx的左和右,也就是说,从这个范围得到下限和上限,然后检查数字是否在界限之间,即

list(lower <= 900 <= upper for (lower, upper) in zip(idx.left,idx.right))

或者

^{pr2}$
[True, False, False]

对于小数据

%%timeit
list(lower <= 900 <= upper for (lower, upper) in zip(idx.left,idx.right))
100000 loops, best of 3: 11.26 µs per loop

%%timeit
[900 in y for y in idx]
100000 loops, best of 3: 9.26 µs per loop

对于大数据

idx = pd.IntervalIndex.from_tuples(data*10000)

%%timeit
list(lower <= 900 <= upper for (lower, upper) in zip(idx.left,idx.right))
10 loops, best of 3: 29.2 ms per loop

%%timeit
[900 in y for y in idx]
10 loops, best of 3: 64.6 ms per loop

这种方法比你的大数据解决方案要好。在

如果您对性能感兴趣,IntervalIndex会针对搜索进行优化。使用.get_loc或{}使用内部构建的IntervalTree(类似于二叉树),它是在第一次使用时构造的。在

In [29]: idx = pd.IntervalIndex.from_tuples(data*10000)

In [30]: %timeit -n 1 -r 1 idx.map(lambda x: 900 in x)
92.8 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

In [40]: %timeit -n 1 -r 1 idx.map(lambda x: 900 in x)
42.7 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

# construct tree and search
In [31]: %timeit -n 1 -r 1 idx.get_loc(900)
4.55 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

# subsequently
In [32]: %timeit -n 1 -r 1 idx.get_loc(900)
137 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

# for a single indexer you can do even better (note that this is
# dipping into the impl a bit
In [27]: %timeit np.arange(len(idx))[(900 > idx.left) & (900 <= idx.right)]
203 µs ± 1.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

请注意.get_loc()返回一个索引器(这实际上比布尔数组更有用,但它们可以相互转换)。在

^{pr2}$

返回布尔数组将转换为索引器数组

In [5]: np.arange(len(idx))[idx.map(lambda x: 900 in x).values.astype(bool)]
Out[5]: array([    0,     3,     6, ..., 29991, 29994, 29997])

这是.get_loc()和.get_indexer()返回的内容:

In [6]: np.sort(idx.get_loc(900))
Out[6]: array([    0,     3,     6, ..., 29991, 29994, 29997])

相关问题 更多 >