以非均匀长度的间隔分割时间序列

问题描述

我有一个时间序列,中间有休息时间(没有录音的时间)。一个简化的例子是:

df = pd.DataFrame(
    np.random.rand(13),columns=["values"],index=pd.date_range(start='1/1/2020 11:00:00',end='1/1/2020 23:00:00',freq='H'))
df.iloc[4:7] = np.nan
df.dropna(inplace=True)
df

                     values
2020-01-01 11:00:00 0.100339
2020-01-01 12:00:00 0.054668
2020-01-01 13:00:00 0.209965
2020-01-01 14:00:00 0.551023
2020-01-01 18:00:00 0.495879
2020-01-01 19:00:00 0.479905
2020-01-01 20:00:00 0.250568
2020-01-01 21:00:00 0.904743
2020-01-01 22:00:00 0.686085
2020-01-01 23:00:00 0.188166

现在我想把它分成间隔,这些间隔除以某个时间跨度(例如 2 小时)。在上面的例子中,这将是:


(                       values
 2020-01-01 11:00:00  0.100339
 2020-01-01 12:00:00  0.054668
 2020-01-01 13:00:00  0.209965
 2020-01-01 14:00:00  0.551023,values
 2020-01-01 18:00:00  0.495879
 2020-01-01 19:00:00  0.479905
 2020-01-01 20:00:00  0.250568
 2020-01-01 21:00:00  0.904743
 2020-01-01 22:00:00  0.686085
 2020-01-01 23:00:00  0.188166)

我有点惊讶,因为我认为这是一个常见问题,所以我没有找到任何相关信息。我当前获取每个间隔的开始和结束索引的解决方案是:

def intervals(data: pd.DataFrame,delta_t: timedelta = timedelta(hours=2)):
    data = data.sort_values(by=['event_timestamp'],ignore_index=True)
    breaks = (data['event_timestamp'].diff() > delta_t).astype(bool).values

    ranges = []
    start = 0
    end = start
    for i,e in enumerate(breaks):
        if not e:
            end = i
            if i == len(breaks) - 1:
                ranges.append((start,end))
                start = i
                end = start

        elif i != 0:
            ranges.append((start,end))
            start = i
            end = start

    return ranges

有什么建议可以让我以更聪明的方式做到这一点吗?我怀疑这应该可以使用 groupby 实现。

解决方法

是的,您可以使用非常方便的np.split

dt = pd.Timedelta('2H')
parts = np.split(df,np.where(np.diff(df.index) > dt)[0] + 1)

例如:

>>> parts
[                       values
 2020-01-01 11:00:00  0.557374
 2020-01-01 12:00:00  0.942296
 2020-01-01 13:00:00  0.181189
 2020-01-01 14:00:00  0.758822,values
 2020-01-01 18:00:00  0.682125
 2020-01-01 19:00:00  0.818187
 2020-01-01 20:00:00  0.053515
 2020-01-01 21:00:00  0.572342
 2020-01-01 22:00:00  0.423129
 2020-01-01 23:00:00  0.882215]
,

@Pierre 感谢您的投入。我现在找到了一个对我来说很方便的解决方案:

df['diff'] = df.index.to_series().diff()
max_gap = timedelta(hours=2)

df['gapId'] = 0
df.loc[df['diff'] >= max_gap,['gapId']] = 1
df['gapId'] = df['gapId'].cumsum()

list(df.groupby('gapId'))

给出:

[(0,values                date            diff  gapId
  0     1.0 2020-01-01 11:00:00             NaT     0
  1     1.0 2020-01-01 12:00:00 0 days 01:00:00     0
  2     1.0 2020-01-01 13:00:00 0 days 01:00:00     0
  3     1.0 2020-01-01 14:00:00 0 days 01:00:00     0),(1,values                date            diff  gapId
  7      1.0 2020-01-01 18:00:00 0 days 04:00:00     1
  8      1.0 2020-01-01 19:00:00 0 days 01:00:00     1
  9      1.0 2020-01-01 20:00:00 0 days 01:00:00     1
  10     1.0 2020-01-01 21:00:00 0 days 01:00:00     1
  11     1.0 2020-01-01 22:00:00 0 days 01:00:00     1
  12     1.0 2020-01-01 23:00:00 0 days 01:00:00     1)]