Python 一种获取唯一相交区间数的有效方法
我有一个间隔为Python 一种获取唯一相交区间数的有效方法,python,algorithm,numpy,pandas,Python,Algorithm,Numpy,Pandas,我有一个间隔为 start end 1 10 3 7 8 10 我需要找到与其他数据帧的交点数 value 2 5 9 结果应该是 1 2 2 问题的第二部分比较棘手。 我的带有间隔的数据帧还包含一种类型 start end type 1 10 1 3 7 1 8 10 2 我需要知道许多唯一的(按类型)间隔将被相交。结果应该是: 1 1 2 我想第一部分可以通过numpy.searchsorted完成,但是第二部分呢?让我们调
start end
1 10
3 7
8 10
我需要找到与其他数据帧的交点数
value
2
5
9
结果应该是
1
2
2
问题的第二部分比较棘手。
我的带有间隔的数据帧还包含一种类型
start end type
1 10 1
3 7 1
8 10 2
我需要知道许多唯一的(按类型)间隔将被相交。结果应该是:
1
1
2
我想第一部分可以通过
numpy.searchsorted
完成,但是第二部分呢?让我们调用您的第一个数据帧df
。对于给定的值,可以按如下方式找到相交间隔:
mask = (df['start'] <= value) & (df['end'] >= value)
以下内容将返回相交类型的数量:
len(df['type'][mask].unique())
现在,您可以将
lambda函数应用于值系列:
values = pd.Series([2, 5, 9], name=['value'])
values.apply(lambda value: len(df['type'][(df['start'] <= value) & (df['end'] >= value)].unique()))
values=pd.Series([2,5,9],name=['value'])
values.apply(lambda值:len(df['type'][(df['start']=value)].unique())
DSM使用熊猫显示。按照该模式,我们可以将start
和end
值组合成一列idx
s,第二列(change
)在idx
对应于start
时等于1,在idx
对应于end
时等于-1
df = pd.DataFrame(
{'end': [10, 7, 10], 'start': [1, 3, 8], 'type': [1, 1, 2]})
event = pd.melt(df, id_vars=['type'], var_name='change', value_name='idx')
event['change'] = event['change'].map({'start':1, 'end':-1})
event = event.sort_values(by=['idx'])
# type change idx
# 3 1 1 1
# 4 1 1 3
# 1 1 -1 7
# 5 2 1 8
# 0 1 -1 10
# 2 2 -1 10
现在,由于我们希望跟踪间隔的类型
,我们可以使用event.pivot
将每个类型放置在其自己的列中。取cumsum
计算覆盖idx
的区间数:
event = event.pivot(index='idx', columns='type', values='change').fillna(0).cumsum(axis=0)
# type 1 2
# idx
# 1 1 0
# 3 2 0
# 7 1 0
# 8 1 1
# 10 0 0
对于每个类型
,我们只关心覆盖的值,而不关心覆盖的次数。因此,让我们计算event>0
以找到包含的值:
event = event > 0
# type 1 2
# idx
# 1 True False
# 3 True False
# 7 True False
# 8 True True
# 10 False False
现在,我们可以使用searchsorted
查找所需的结果:
other = pd.DataFrame({'value': [2, 5, 9]})
idx = event.index.searchsorted(other['value'])-1
other['result'] = event.iloc[idx].sum(axis=1).values
总而言之:
import numpy as np
import pandas as pd
df = pd.DataFrame(
{'end': [10, 7, 10], 'start': [1, 3, 8], 'type': [1, 1, 2]})
event = pd.melt(df, id_vars=['type'], var_name='change', value_name='idx')
event['change'] = event['change'].map({'start':1, 'end':-1})
event = event.sort_values(by=['idx'])
event = event.pivot(index='idx', columns='type', values='change').fillna(0).cumsum(axis=0)
event = event > 0
other = pd.DataFrame({'value': [2, 5, 9]})
idx = event.index.searchsorted(other['value'])-1
other['result'] = event.iloc[idx].sum(axis=1).values
print(other)
屈服
value result
0 2 1
1 5 1
2 9 2
value result
0 0 0
1 1 0 <-- The half-open interval (1, 10] does not include 1
2 2 1
3 3 1
4 4 1
5 5 1
6 6 1
7 7 1
8 8 1 <-- The half-open interval (8, 10] does not include 8
9 9 2
10 10 2
11 11 0
12 12 0
为了检查计算的正确性,让我们看看
other = pd.DataFrame({'value': np.arange(13)})
然后
屈服
value result
0 2 1
1 5 1
2 9 2
value result
0 0 0
1 1 0 <-- The half-open interval (1, 10] does not include 1
2 2 1
3 3 1
4 4 1
5 5 1
6 6 1
7 7 1
8 8 1 <-- The half-open interval (8, 10] does not include 8
9 9 2
10 10 2
11 11 0
12 12 0
在第二行中,类型为1。如果另一数据帧中的值为5,则[1,10]和[3,7]都相交。因此,结果(即相交的唯一间隔数)不应该是
[1,2,2]
而不是[1,1,2]
?如果你做了第一部分并向我们展示了你的代码,那么第二部分就更容易帮助你了。@unutbu[1,10]和[3,7]都属于同一类型(类型1),因此,只有一种类型的间隔5相交。这不是唯一的间隔,而是唯一的类型。我关心的是代码的效率。它能以100%广播的方式实现吗?我知道我们需要unutbu来拯救:)
idx = event.index.searchsorted(other['value'], side='right')-1