根据间隔重叠合并两个数据帧
Merge two dataframes based on interval overlap
我有两个数据框 A 和 B:
例如:
import pandas as pd
import numpy as np
In [37]:
A = pd.DataFrame({'Start': [10, 11, 20, 62, 198], 'End': [11, 11, 35, 70, 200]})
A[["Start","End"]]
Out[37]:
Start End
0 10 11
1 11 11
2 20 35
3 62 70
4 198 200
In [38]:
B = pd.DataFrame({'Start': [8, 5, 8, 60], 'End': [10, 90, 13, 75], 'Info': ['some_info0','some_info1','some_info2','some_info3']})
B[["Start","End","Info"]]
Out[38]:
Start End Info
0 8 10 some_info0
1 5 90 some_info1
2 8 13 some_info2
3 60 75 some_info3
我想根据 A 的间隔(开始-结束)是否与 B 的间隔重叠,将列信息添加到数据帧 A。如果 A 间隔与多个 B 间隔重叠,则信息应添加对应较短的间隔。
我一直在寻找如何解决这个问题,我发现了一些类似的问题,但他们的大部分答案都使用 iterrows()
,在我的情况下,因为我正在处理巨大的数据帧是不可行的.
我想要这样的东西:
A.merge(B,on="overlapping_interval", how="left")
然后删除重复项,保留来自较短间隔的信息。
输出应如下所示:
In [39]:
C = pd.DataFrame({'Start': [10, 11, 20, 62, 198], 'End': [11, 11, 35, 70, 200], 'Info': ['some_info0','some_info2','some_info1','some_info3',np.nan]})
C[["Start","End","Info"]]
Out[39]:
Start End Info
0 10 11 some_info0
1 11 11 some_info2
2 20 35 some_info1
3 62 70 some_info3
4 198 200 NaN
我发现 非常有趣,因为它暗示了使用 pandas Interval 对象解决此问题的可能性。但经过多次尝试,我还没有设法解决它。
有什么想法吗?
我建议做一个函数然后应用到行上:
首先我计算 B
中的增量(结束 - 开始)用于排序目的
B['delta'] = B.End - B.Start
然后是获取信息的函数:
def get_info(x):
#Fully included
c0 = (x.Start >= B.Start) & (x.End <= B.End)
#start lower, end include
c1 = (x.Start <= B.Start) & (x.End >= B.Start)
#start include, end higher
c2 = (x.Start <= B.End) & (x.End >= B.End)
#filter with conditions and sort by delta
_B = B[c0|c1|c2].sort_values('delta',ascending=True)
return None if len(_B) == 0 else _B.iloc[0].Info #None if no info corresponding
那么你可以把这个函数应用到A
:
A['info'] = A.apply(lambda x : get_info(x), axis='columns')
print(A)
Start End info
0 10 11 some_info0
1 11 11 some_info2
2 20 35 some_info1
3 62 70 some_info3
4 198 200 None
注:
- 而不是使用
pd.Interval
,创建您自己的条件。 cx
是您的间隔定义,更改它们以获得确切的预期行为
我有两个数据框 A 和 B:
例如:
import pandas as pd
import numpy as np
In [37]:
A = pd.DataFrame({'Start': [10, 11, 20, 62, 198], 'End': [11, 11, 35, 70, 200]})
A[["Start","End"]]
Out[37]:
Start End
0 10 11
1 11 11
2 20 35
3 62 70
4 198 200
In [38]:
B = pd.DataFrame({'Start': [8, 5, 8, 60], 'End': [10, 90, 13, 75], 'Info': ['some_info0','some_info1','some_info2','some_info3']})
B[["Start","End","Info"]]
Out[38]:
Start End Info
0 8 10 some_info0
1 5 90 some_info1
2 8 13 some_info2
3 60 75 some_info3
我想根据 A 的间隔(开始-结束)是否与 B 的间隔重叠,将列信息添加到数据帧 A。如果 A 间隔与多个 B 间隔重叠,则信息应添加对应较短的间隔。
我一直在寻找如何解决这个问题,我发现了一些类似的问题,但他们的大部分答案都使用 iterrows()
,在我的情况下,因为我正在处理巨大的数据帧是不可行的.
我想要这样的东西:
A.merge(B,on="overlapping_interval", how="left")
然后删除重复项,保留来自较短间隔的信息。
输出应如下所示:
In [39]:
C = pd.DataFrame({'Start': [10, 11, 20, 62, 198], 'End': [11, 11, 35, 70, 200], 'Info': ['some_info0','some_info2','some_info1','some_info3',np.nan]})
C[["Start","End","Info"]]
Out[39]:
Start End Info
0 10 11 some_info0
1 11 11 some_info2
2 20 35 some_info1
3 62 70 some_info3
4 198 200 NaN
我发现
有什么想法吗?
我建议做一个函数然后应用到行上:
首先我计算 B
中的增量(结束 - 开始)用于排序目的
B['delta'] = B.End - B.Start
然后是获取信息的函数:
def get_info(x):
#Fully included
c0 = (x.Start >= B.Start) & (x.End <= B.End)
#start lower, end include
c1 = (x.Start <= B.Start) & (x.End >= B.Start)
#start include, end higher
c2 = (x.Start <= B.End) & (x.End >= B.End)
#filter with conditions and sort by delta
_B = B[c0|c1|c2].sort_values('delta',ascending=True)
return None if len(_B) == 0 else _B.iloc[0].Info #None if no info corresponding
那么你可以把这个函数应用到A
:
A['info'] = A.apply(lambda x : get_info(x), axis='columns')
print(A)
Start End info
0 10 11 some_info0
1 11 11 some_info2
2 20 35 some_info1
3 62 70 some_info3
4 198 200 None
注:
- 而不是使用
pd.Interval
,创建您自己的条件。cx
是您的间隔定义,更改它们以获得确切的预期行为