Pandas - 按连续日期时间段分组

Pandas - groupby continuous datetime periods

我有一个 pandas 数据框,如下所示:

    KEY   START       END         VALUE
0   A     2017-01-01  2017-01-16  2.1
1   B     2017-01-01  2017-01-23  4.3
2   B     2017-01-23  2017-02-10  1.7
3   A     2017-01-28  2017-02-02  4.2
4   A     2017-02-02  2017-03-01  0.8  

我想 groupbyKEYsumVALUE 但仅限连续的时间段。例如在上面的例子中我想得到:

   KEY  START       END         VALUE 
0  A    2017-01-01  2017-01-16  2.1
1  A    2017-01-28  2017-03-01  5.0
2  B    2017-01-01  2017-02-10  6.0

A有两个小组,因为时间段有差距。 我想避免 for 循环,因为数据框有数千万行。

通过比较每组 shifted START 列来创建助手 Series,并将其用于 groupby:

s = df.loc[df.groupby('KEY')['START'].shift(-1) == df['END'], 'END']
s = s.combine_first(df['START'])
print (s)
0   2017-01-01
1   2017-01-23
2   2017-01-23
3   2017-02-02
4   2017-02-02
Name: END, dtype: datetime64[ns]

df = df.groupby(['KEY', s], as_index=False).agg({'START':'first','END':'last','VALUE':'sum'})
print (df)
  KEY  VALUE      START        END
0   A    2.1 2017-01-01 2017-01-16
1   A    5.0 2017-01-28 2017-03-01
2   B    6.0 2017-01-01 2017-02-10

如果只有两个连续的行要聚合,jezrael 的回答就像一个魅力。在新示例中,它不会聚合 KEY = A.

的最后三行
     KEY   START       END         VALUE
 0   A     2017-01-01  2017-01-16  2.1
 1   B     2017-01-01  2017-01-23  4.3
 2   B     2017-01-23  2017-02-10  1.7
 3   A     2017-01-28  2017-02-02  4.2
 4   A     2017-02-02  2017-03-01  0.8 
 5   A     2017-03-01  2017-03-23  1.0

以下解决方案(对 jezrael 的解决方案稍作修改)可以聚合所有应聚合的行:

df = df.sort_values(by='START')
idx = df.groupby('KEY')['START'].shift(-1) != df['END']
df['DATE'] = df.loc[idx, 'START']
df['DATE'] = df.groupby('KEY').DATE.fillna(method='backfill')
df = (df.groupby(['KEY', 'DATE'], as_index=False)
        .agg({'START': 'first', 'END': 'last', 'VALUE': 'sum'})
        .drop(['DATE'], axis=1))

给出:

   KEY   START         END      VALUE
0   A  2017-01-01  2017-01-16    2.1
1   A  2017-01-28  2017-03-23    6.0
2   B  2017-01-01  2017-02-10    6.0

感谢@jezrael 的优雅方法!