根据不同日期重新采样时间序列

Posted

技术标签:

【中文标题】根据不同日期重新采样时间序列【英文标题】:Resample time series based on different dates 【发布时间】:2021-12-31 08:56:26 【问题描述】:

我有一个表df1,它由不同的ID 表示的多个时间序列组成。我想根据另一个表df2 中的开始和结束日期对每个ID 的时间序列进行重新采样。 df1df2如下:

df1:

            Index       Timestamp               Data    ID
0           1           2010-03-04 13:16:44.310 125.0   1
4           6           2010-03-04 13:17:01.777 130.0   1   
5           7           2010-03-04 13:17:01.943 135.0   1   
12          16          2010-03-04 13:19:19.997 135.0   1   
16          21          2010-03-04 13:19:27.047 135.0   1   
... ... ... ... ... ...
45863344    45871285    2010-11-30 17:07:54.730 126.0   26  
45863345    45871286    2010-11-30 17:08:00.367 125.5   26  
45883410    45892266    2010-12-01 15:03:11.587 125.5   26  
45883411    45892267    2010-12-01 15:03:12.587 145.0   26  
45883619    45892475    2010-12-01 15:25:04.097 185.0   26  

df2:

    End Date    Start Date    ID     Name  ...
0   2010-12-03  2010-11-23    1      AA01  ...
1   2010-04-07  2010-03-28    26     BB10  ...
    ... ... ... ... ... ...

对于每个ID,我对时间序列进行了重新采样,以在从2010-01-012010-01-11 的10 天内每分钟有一个日期点,这可以通过以下方法实现:

start = '2010-01-01'
end = '2010-01-11'

def f(x):
    r = pd.date_range(start=start, end = end, freq='1min')
    return x.reindex(r, method='ffill').bfill()


df_sub = (df1
        .set_index('Timestamp')
        .groupby('ID', sort=False)['Data']
        .apply(f)
        .rename_axis(['ID','Timestamp'])
        .reset_index()
        )

但是对于所有ID,这是基于2010-01-012010-01-11 的相同开始和结束日期。有没有办法从df2 为每个ID 引入不同的开始和结束日期,例如,对于ID 1 我只提取2010-11-232010-12-03 之间的时间序列,而对于ID 26 只提取时间2010-03-282010-04-07 之间的系列?

输出如下所示:

        ID  Timestamp           Data
0       1   2010-12-03 00:00:00 125.5
1       1   2010-12-03 00:01:00 125.5
2       1   2010-12-03 00:02:00 185.5
3       1   2010-12-03 00:03:00 225.5
4       1   2010-12-03 00:04:00 215.5
... ... ... ... ...
2167409 26  2020-12-09 23:55:00 125.0
2167410 26  2010-12-09 23:56:00 135.0
2167411 26  2010-12-09 23:57:00 145.0
2167412 26  2010-12-09 23:58:00 125.0
... ... ... ... ...

复制示例: df1:

from pandas import Timestamp

df1 = pd.DataFrame('Index': (2, 1): 2,
  (2, 6): 8,
  (2, 37): 47,
  (2, 81): 92,
  (2, 88): 101,
  (2, 132): 146,
  (2, 139): 155,
  (2, 436): 453,
  (2, 545): 564,
  (2, 816): 835,
  (10, 172): 188,
  (10, 450): 469,
  (10, 565): 584,
  (10, 830): 849,
  (10, 1000): 1019,
  (10, 271312): 271331,
  (10, 271313): 271332,
  (10, 271314): 271333,
  (10, 271315): 271334,
  (10, 271316): 271335,
  (120, 1614): 1633,
  (120, 1665): 1684,
  (120, 1666): 1685,
  (120, 1733): 1752,
  (120, 1734): 1753,
  (120, 1835): 1854,
  (120, 1836): 1855,
  (120, 1957): 1976,
  (120, 1958): 1977,
  (120, 2091): 2110,
 'Timestamp': (2, 1): Timestamp('2014-03-04 13:16:44.310000'),
  (2, 6): Timestamp('2014-03-04 13:17:01.777000'),
  (2, 37): Timestamp('2014-04-17 11:59:57.470000'),
  (2, 81): Timestamp('2014-04-17 12:01:08.973000'),
  (2, 88): Timestamp('2014-04-17 12:05:55.153000'),
  (2, 132): Timestamp('2014-04-17 12:08:58.933000'),
  (2, 139): Timestamp('2014-04-17 12:35:58.290000'),
  (2, 436): Timestamp('2014-04-17 12:41:42.147000'),
  (2, 545): Timestamp('2014-04-17 12:46:14.450000'),
  (2, 816): Timestamp('2014-04-17 13:05:53.077000'),
  (10, 172): Timestamp('2014-04-17 12:35:58.633000'),
  (10, 450): Timestamp('2014-04-17 12:41:42.067000'),
  (10, 565): Timestamp('2014-04-17 12:46:14.747000'),
  (10, 830): Timestamp('2014-04-17 13:05:53.153000'),
  (10, 1000): Timestamp('2014-04-17 13:10:20.127000'),
  (10, 271312): Timestamp('2014-05-13 14:59:44.627000'),
  (10, 271313): Timestamp('2014-05-13 14:59:44.780000'),
  (10, 271314): Timestamp('2014-05-13 14:59:45.600000'),
  (10, 271315): Timestamp('2014-05-13 14:59:45.757000'),
  (10, 271316): Timestamp('2014-05-13 14:59:46.687000'),
  (120, 1614): Timestamp('2014-04-17 15:39:52.673000'),
  (120, 1665): Timestamp('2014-04-17 15:46:41.260000'),
  (120, 1666): Timestamp('2014-04-17 15:46:41.417000'),
  (120, 1733): Timestamp('2014-04-17 16:07:54.657000'),
  (120, 1734): Timestamp('2014-04-17 16:07:54.817000'),
  (120, 1835): Timestamp('2014-04-17 16:23:59.943000'),
  (120, 1836): Timestamp('2014-04-17 16:24:00.103000'),
  (120, 1957): Timestamp('2014-04-17 16:53:00.543000'),
  (120, 1958): Timestamp('2014-04-17 16:53:00.703000'),
  (120, 2091): Timestamp('2014-04-17 17:29:21.163000'),
 'Data': (2, 1): 30.0,
  (2, 6): 30.0,
  (2, 37): 25.0,
  (2, 81): 25.0,
  (2, 88): 25.0,
  (2, 132): 25.0,
  (2, 139): 25.0,
  (2, 436): 25.0,
  (2, 545): 25.0,
  (2, 816): 25.0,
  (10, 172): 25.0,
  (10, 450): 25.0,
  (10, 565): 25.0,
  (10, 830): 25.0,
  (10, 1000): 25.0,
  (10, 271312): 25.0,
  (10, 271313): 27.5,
  (10, 271314): 27.5,
  (10, 271315): 30.5,
  (10, 271316): 30.5,
  (120, 1614): 31.0,
  (120, 1665): 30.5,
  (120, 1666): 30.0,
  (120, 1733): 29.5,
  (120, 1734): 29.0,
  (120, 1835): 28.5,
  (120, 1836): 28.0,
  (120, 1957): 27.5,
  (120, 1958): 27.0,
  (120, 2091): 26.5,
 'ID': (2, 1): 2,
  (2, 6): 2,
  (2, 37): 2,
  (2, 81): 2,
  (2, 88): 2,
  (2, 132): 2,
  (2, 139): 2,
  (2, 436): 2,
  (2, 545): 2,
  (2, 816): 2,
  (10, 172): 10,
  (10, 450): 10,
  (10, 565): 10,
  (10, 830): 10,
  (10, 1000): 10,
  (10, 271312): 10,
  (10, 271313): 10,
  (10, 271314): 10,
  (10, 271315): 10,
  (10, 271316): 10,
  (120, 1614): 120,
  (120, 1665): 120,
  (120, 1666): 120,
  (120, 1733): 120,
  (120, 1734): 120,
  (120, 1835): 120,
  (120, 1836): 120,
  (120, 1957): 120,
  (120, 1958): 120,
  (120, 2091): 120
  )

df2:

df2 = pd.DataFrame('ID': 8: 10, 9: 2, 116: 120,
 'Start Date': 8: Timestamp('2014-04-20 00:00:00'),
  9: Timestamp('2014-03-04 00:00:00'),
  116: Timestamp('2014-04-17 00:00:00'),
 'End Date': 8: Timestamp('2014-04-30 00:00:00'),
  9: Timestamp('2014-03-14 00:00:00'),
  116: Timestamp('2014-04-27 00:00:00'),
 'comment': 8: 'TBA', 9: 'TBA', 116: 'TBA',
 'Name': 8: 'NN95', 9: 'AA01', 116: 'BB10')

df2

【问题讨论】:

您能否分享代码以生成示例输入数据,以便我们帮助您开发解决方案? 嗨@erap129,请参阅编辑后的问题以获取示例数据。谢谢 【参考方案1】:

我认为这应该可行。只需加入df1df2 即可获取每个ID 的开始和结束日期。如果我没有抓住重点,请告诉我。

def f(sub_df):
    r = pd.date_range(start=sub_df['Start Date'].iloc[0], end=sub_df['End Date'].iloc[0], freq='1min')
    return sub_df.reindex(r, method='ffill').bfill()['Data']


df_sub = (pd.merge(df1, df2, on='ID')
        .set_index('Timestamp')
        .groupby('ID', sort=False)
        .apply(f)
        .rename_axis(['ID','Timestamp'])
        .reset_index()
        )

编辑:如果df2 中的相同ID 可以与多个开始日期、结束日期对关联,请使用以下方法:

def f(sub_df):
    r = pd.date_range(start=sub_df['Start Date'].iloc[0], end=sub_df['End Date'].iloc[0], freq='1min')
    return sub_df.reindex(r, method='ffill').bfill()['Data']

df2['group_id'] = df2.index

df_sub = pd.merge(df1, df2, on='ID').\
    set_index('Timestamp').\
    groupby(['ID', 'group_id'], sort=False).\
    apply(f).\
    rename_axis(['ID', 'group_id', 'Timestamp']).\
    reset_index().drop(columns=['group_id'])

【讨论】:

嘿,erap129,这很好用!我确实有一个问题 - 为什么我们需要sub_df['Start Date'].iloc[0] 中的.iloc[0] 来提取f 中的开始和结束日期? 因为我合并了df1df2,所以每次测量都包含开始和结束日期。这意味着合并的数据帧中有冗余数据,但我认为它简化了事情,因为我们可以在单个数据帧上执行所有操作。 嘿,erap129,刚刚意识到另一个问题 - ID 可能有重复项,但开始和结束日期不同。我尝试在df_sub 中使用groupby(['ID','Timestamp']),但遇到错误ValueError: Length of names must match number of levels in MultiIndex. 另外,与使用 for-loop 的替代方法相比,它似乎没有收集所有数据。 是的,如果ID 具有不同的开始日期和结束日期,我明白你的意思。在这种情况下,我会使用df2 的索引作为分组值。通过这种方式,您允许同一 ID 的重复日期范围,请参阅我编辑的答案。关于“与使用 for-loop 的替代方法相比,不提取所有数据点”,你能举个例子吗?

以上是关于根据不同日期重新采样时间序列的主要内容,如果未能解决你的问题,请参考以下文章

使用另一个时间序列的索引重新采样一个时间序列

pyspark:在日期和时间上重新采样 pyspark 数据帧

熊猫数据框每天重新采样,没有日期时间索引

熊猫数据框每天重新采样,没有日期时间索引

在 pandas 中有效地聚合重新采样的日期时间集合

使用 Pandas 将每日数据重新采样为每月(日期格式)