Python 如何按自定义重叠时段对数据帧进行分组?

Python 如何按自定义重叠时段对数据帧进行分组?,python,pandas,group-by,pandas-groupby,period,Python,Pandas,Group By,Pandas Groupby,Period,假设我有一个列表列表,其中每个嵌套列表有两个值:一个范围的开始日期和一个范围的结束日期。比如说: ranges_list = [ ['2020-03-12', '2020-06-12'], ['2020-03-13', '2020-06-13'], ['2020-03-14', '2020-06-14'] ] 这代表3个范围: 2020年3月12日至2020年6月12日 2020年3月13日至2020年6月13日 2020年3月14日至2020年6月14日 假设我还有一

假设我有一个列表列表,其中每个嵌套列表有两个值:一个范围的开始日期和一个范围的结束日期。比如说:

ranges_list = [
    ['2020-03-12', '2020-06-12'],
    ['2020-03-13', '2020-06-13'],
    ['2020-03-14', '2020-06-14']
]
这代表3个范围:

  • 2020年3月12日至2020年6月12日
  • 2020年3月13日至2020年6月13日
  • 2020年3月14日至2020年6月14日
  • 假设我还有一个数据框
    d
    ,它有多个列,其中一个是名为
    'occurrence\u date'
    的列,其中包含日期时间

    假设数据帧
    d
    看起来像:

    ID      LinkID   PC    occurence_date
    10R46   R*1005   8017  2020-03-12
    10R46   R*10335  5019  2020-04-15
    100R91  R*1005   8017  2020-04-15
    10R91   R*243    8870  2020-06-14
    
    我想使用
    ranges\u列表中指定的范围上的
    occurrence\u date
    列对数据帧
    d
    进行分组

    比如:

    grouped = d.groupby('occurence_date', ranges=ranges_list)
    
    显然,这个groupby代码是不正确的,但有助于服务于我想做的事情

    最后,分组对象应该有3个不同的组,如下所示:

    group: ('2020-03-12', '2020-06-12')
    ID      LinkID   PC    occurence_date
    10R46   R*1005   8017  2020-03-12
    10R46   R*10335  5019  2020-04-15
    100R91  R*1005   8017  2020-04-15
    
    group: ('2020-03-13', '2020-06-13')
    ID      LinkID   PC    occurence_date
    10R46   R*10335  5019  2020-04-15
    100R91  R*1005   8017  2020-04-15
    
    group: ('2020-03-14', '2020-06-14')
    ID      LinkID   PC    occurence_date
    10R46   R*10335  5019  2020-04-15
    100R91  R*1005   8017  2020-04-15
    10R91   R*243    8870  2020-06-14
    

    我怎样才能做到这一点呢?

    您可以通过
    pd.IntervalIndex
    进行分组:

    ranges_list = [
        (pd.Timestamp('2020-03-12'), pd.Timestamp('2020-06-12')),
        (pd.Timestamp('2020-03-13'), pd.Timestamp('2020-06-13')),
        (pd.Timestamp('2020-03-14'), pd.Timestamp('2020-06-14'))
    ]
    
    idx = pd.IntervalIndex.from_tuples(ranges_list, closed='both')
    
    def in_ranges(x, bins):
        rv = []
        for b in bins:
            if x in b:
                rv.append(b)
        return rv
    
    df['groups'] = df['occurence_date'].apply(lambda x: in_ranges(x, idx))
    
    for g in df.explode('groups').groupby('groups'):
        print(g[0])
        print('-' * 80)
        print(g[1][['ID', 'LinkID', 'PC', 'occurence_date']])
        print()
    
    印刷品:

    [2020-03-12, 2020-06-12]
    --------------------------------------------------------------------------------
           ID   LinkID    PC occurence_date
    0   10R46   R*1005  8017     2020-03-12
    1   10R46  R*10335  5019     2020-04-15
    2  100R91   R*1005  8017     2020-04-15
    
    [2020-03-13, 2020-06-13]
    --------------------------------------------------------------------------------
           ID   LinkID    PC occurence_date
    1   10R46  R*10335  5019     2020-04-15
    2  100R91   R*1005  8017     2020-04-15
    
    [2020-03-14, 2020-06-14]
    --------------------------------------------------------------------------------
           ID   LinkID    PC occurence_date
    1   10R46  R*10335  5019     2020-04-15
    2  100R91   R*1005  8017     2020-04-15
    3   10R91    R*243  8870     2020-06-14
    

    下面的交互式会话将演示如何获得必要的数据,以便根据需要将记录分组在一起。可能有一种更有效的方法,因为这将迭代
    len(d)*len(dranges)
    ,但如果您没有大量数据,这是一种简单的解决方案

    >>> d
           ID   LinkID    PC occurence_date
    0   10R46   R*1005  8017     2020-03-12
    1   10R46  R*10335  5019     2020-04-15
    2  100R91   R*1005  8017     2020-04-15
    3   10R91    R*243  8870     2020-06-14
    
    >>> dranges
                0           1
    0  2020-03-12  2020-06-12
    1  2020-03-13  2020-06-13
    2  2020-03-14  2020-06-14
    
    >>> d['overlaps'] = d.apply(lambda row: [f'{dr[0]} to {dr[1]}' 
                                             for _, dr in dranges.iterrows() 
                                             if row['occurence_date'] >= dr[0] 
                                             and row['occurence_date'] <= dr[1]]
                               , axis=1)
    
    >>> d.explode('overlaps').sort_values('overlaps')
           ID   LinkID    PC occurence_date                  overlaps
    0   10R46   R*1005  8017     2020-03-12  2020-03-12 to 2020-06-12
    1   10R46  R*10335  5019     2020-04-15  2020-03-12 to 2020-06-12
    2  100R91   R*1005  8017     2020-04-15  2020-03-12 to 2020-06-12
    1   10R46  R*10335  5019     2020-04-15  2020-03-13 to 2020-06-13
    2  100R91   R*1005  8017     2020-04-15  2020-03-13 to 2020-06-13
    1   10R46  R*10335  5019     2020-04-15  2020-03-14 to 2020-06-14
    2  100R91   R*1005  8017     2020-04-15  2020-03-14 to 2020-06-14
    3   10R91    R*243  8870     2020-06-14  2020-03-14 to 2020-06-14
    
    >>d
    ID LinkID PC发生日期\u
    0 10R46 R*1005 8017 2020-03-12
    1 10R46 R*10335 5019 2020-04-15
    2 100R91 R*1005 8017 2020-04-15
    3 10R91 R*243 8870 2020-06-14
    >>>德兰吉斯
    0           1
    0  2020-03-12  2020-06-12
    1  2020-03-13  2020-06-13
    2  2020-03-14  2020-06-14
    >>>d['overlaps']=d.apply(lambda行:[f'{dr[0]}到{dr[1]}'
    例如,dr in dranges.iterrows()
    如果行['occurrence\u date']>=dr[0]
    和行['occurrence\u date']>>d.explode('overlaps')。排序\u值('overlaps'))
    ID LinkID PC发生\u日期重叠
    0 10R46 R*1005 8017 2020-03-12 2020-03-12至2020-06-12
    1 10R46 R*10335 5019 2020-04-15 2020-03-12至2020-06-12
    2 100R91 R*1005 8017 2020-04-15 2020-03-12至2020-06-12
    1 10R46 R*10335 5019 2020-04-15 2020-03-13至2020-06-13
    2 100R91 R*1005 8017 2020-04-15 2020-03-13至2020-06-13
    1 10R46 R*10335 5019 2020-04-15 2020-03-14至2020-06-14
    2 100R91 R*1005 8017 2020-04-15 2020-03-14至2020-06-14
    3 10R91 R*243 8870 2020-06-14 2020-03-14至2020-06-14