代码之家  ›  专栏  ›  技术社区  ›  Pau RS

基于间隔重叠合并两个数据帧

  •  0
  • Pau RS  · 技术社区  · 6 年前

    我有两个数据帧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
    

    我找到了 this question 非常有趣,因为它表明了使用pandas Interval对象解决此问题的可能性。但经过多次尝试,我都没能解决这个问题。

    有什么想法吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   David Leon    6 年前

    我建议执行一个函数,然后应用于行:

    首先,我计算 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 如果是间隔定义,请更改它们以获得准确的预期行为