我有一个pandas数据帧INT,有两个整数列,START和END,表示间隔[START,END]。我需要检查整数POS是否属于这些间隔之一,即,如果存在START< = POS< = END的行。我需要为成千上万的POS做到这一点,我有数千个间隔。所有内容都按时间间隔和POS值进行排序。
我认为这是一个有效的解决方案,按顺序检查POS值并跟踪最后最近的间隔,以便我可以开始希望接近我想要的间隔(如果存在)并且我只需要在区间表中前进以检查是否有一个:
max_inter = max(intervals.END - intervals.START)
last_index = 0
def find(POS):
global last_index, max_inter, intervals
i = last_index
while i > 0 and intervals.START.iloc[i] > POS - max_inter:
i -= 1
found = False
while i < len(intervals) - 1 and intervals.START.iloc[i]) <= POS:
if intervals.START.iloc[i] <= POS and POS <= intervals.END.iloc[i]:
found = True
break
i += 1
last_index = i
return found
然而,这比我想要的要慢,因为它是纯粹的python,在pandas或numpy中有没有一种有效的方法呢?
我已经尝试了类似
的内容any((intervals.START <= POS) & (POS <= intervals.END))
但这比我的解决方案要慢得多。有什么建议吗?我错过了库函数吗?
由于
编辑:也许我应该提到我有一个(排序的)POS系列值我需要检查,我目前正在使用positions.map(find)
来生成一个布尔系列,也许有更好的方法来做到这一点。此外,我必须为数千个位置和间隔执行此操作,这就是我对速度感兴趣的原因。
答案 0 :(得分:0)
您可以使用boolean indexing,例如SO answer
的答案就个人而言,我会使用eval这对大型数组非常有效,如下所示:
import pandas as pd
df = pd.DataFrame([[4,9],[2,5],[3,6],[1,4]], columns=['start','end'])
df
start end
0 4 9
1 2 5
2 3 6
3 1 4
pos = 3
df[df.eval('(start <= {}) & ({} <= end)'.format(pos,pos))]
start end
1 2 5
2 3 6
3 1 4
答案 1 :(得分:0)
虽然这不是纯熊猫,但速度非常快。 NCLS用于在<5秒内找到约5000万个重叠。
安装:
# pip install ncls
# or
# conda install -c bioconda ncls
设置:
import numpy as np
np.random.seed(0)
import pandas as pd
size = int(1e6)
dtype = np.int32
start = np.random.randint(int(1e7), size=size, dtype=dtype)
end = start + np.random.randint(int(1e3), size=size, dtype=dtype)
start2 = np.random.randint(int(1e7), size=size, dtype=dtype)
end2 = start2 + 1
intervals = pd.DataFrame({"Start": start, "End": end})
# Start End
# 0 8325804 8326332
# 1 1484405 1485343
# 2 2215104 2215531
# 3 5157699 5157834
# 4 8222403 8222497
# ... ... ...
# 999995 2981746 2982673
# 999996 1453668 1454251
# 999997 3325111 3325135
# 999998 4311711 4312465
# 999999 8089671 8090277
#
# [1000000 rows x 2 columns]
points = pd.DataFrame({"Start": start2, "End": end2})
# Start End
# 0 1714420 1714421
# 1 980607 980608
# 2 5566444 5566445
# 3 2788107 2788108
# 4 6145575 6145576
# ... ... ...
# 999995 1824809 1824810
# 999996 6135851 6135852
# 999997 5190341 5190342
# 999998 7403307 7403308
# 999999 9732498 9732499
#
# [1000000 rows x 2 columns]
执行:
from ncls import NCLS
n = NCLS(intervals.Start.values, intervals.End.values, intervals.index.values)
# Wall time: 421 ms
p_ix, i_ix = n.all_overlaps_both(points.Start.values, points.End.values, points.index.values)
# Wall time: 4.4s
len(i_ix) / 1e6
# 49.895545
i = intervals.reindex(i_ix).reset_index(drop=True)
p = points.reindex(p_ix).reset_index(drop=True)
p.columns = ["PStart", "PEnd"]
result = pd.concat([i, p], axis=1)
print(result)
# Start End PStart PEnd
# 0 1713535 1714442 1714420 1714421
# 1 1713560 1714479 1714420 1714421
# 2 1713670 1714590 1714420 1714421
# 3 1713677 1714666 1714420 1714421
# 4 1713694 1714627 1714420 1714421
# ... ... ... ... ...
# 49895540 9732449 9732910 9732498 9732499
# 49895541 9732491 9733159 9732498 9732499
# 49895542 9732492 9732621 9732498 9732499
# 49895543 9732496 9732653 9732498 9732499
# 49895544 9732496 9732512 9732498 9732499
#
# [49895545 rows x 4 columns]