Pandas 将时间序列数据重新采样为 15 分钟和 45 分钟 - 使用多索引或列

Posted

技术标签:

【中文标题】Pandas 将时间序列数据重新采样为 15 分钟和 45 分钟 - 使用多索引或列【英文标题】:Pandas resample timeseries data to 15 mins and 45 mins - using multi-index or column 【发布时间】:2019-01-13 07:01:21 【问题描述】:

我有一些时间序列数据作为 Pandas 数据框,从每小时过去 15 分钟和过去 45 分钟(时间间隔为 30 分钟)开始观察,然后将频率更改为每分钟。我想对数据进行重新采样,使其在整个数据帧的每 30 分钟、15 点和 45 点的常规频率。

我想到了两种方法来实现这一点。 1. 使用时间序列数据作为数据框中的一列,只需过滤 15 分钟和 45 分钟的所有观测值的数据框。 2. 重新设置索引,使时间序列数据成为多索引的一部分(索引的第 0 级是气象站,第 1 级是观测时间)并使用 Pandas 日期时间时间序列resample() 等功能。

原始数据框,天气,如下所示:

                  parsed_time           Pressure  Temp    Hum
Station   (index)   
Bow       1        2018-04-15 14:15:00   1012     20.0    87
          2        2018-04-15 14:45:00   1013     20.0    87
          3        2018-04-15 15:15:00   1012     21.0    87
          4        2018-04-15 15:45:00   1014     22.0    86
          5        2018-04-15 16:00:00   1015     22.0    86
          6        2018-04-15 16:01:00   1012     25.0    86
          7        2018-04-15 16:02:00   1012     25.0    86
Stratford 8        2018-04-15 14:15:00   1011     18.0    87
          9        2018-04-15 14:45:00   1011     18.0    87
          10       2018-04-15 15:15:00   1012     18.0    87
          11       2018-04-15 15:45:00   1014     19.0    86
          12       2018-04-15 16:00:00   1014     19.0    86
          13       2018-04-15 16:01:00   1015     19.0    86
          14       2018-04-15 16:02:00   1016     20.0    86
          15       2018-04-15 16:04:00   1016     20.0    86

使用方法 1,我的布尔选择操作似乎无法按预期工作。例如

weather_test = weather[weather['parsed_time'].dt.minute == (15 & 45)]

像这样给出 parsed_time 值:

2018-04-15 14:13:002018-04-15 15:13:00

weather_test = weather[weather['parsed_time'].dt.minute == (15 | 45)]

产生如下 parsed_time 值:

2018-04-15 14:47:002018-04-15 14:47:00

我在文档中找不到任何东西来解释这种行为。我想要的是以下时间点的压力、温度、湿度:

2018-04-15 14:45:00    
2018-04-15 15:15:00  
2018-04-15 15:45:00
2018-04-15 16:15:00

等等。

使用方法 2,我想对数据进行重新采样,以便用前 30 分钟的平均值替换我拥有每分钟数据的观察结果。此功能似乎仅在 parsed_time 列是索引的一部分时才有效,因此我使用以下代码将 parsed_time 设置为多索引的一部分:

weather.set_index('parsed_time', append=True, inplace=True)
weather.index.set_names('station', level=0, inplace=True)
weather = weather.reset_index(level=1, drop=True)

最终得到如下所示的数据框:

                                  Pressure   Temp    Hum
Station    parsed_time
Bow            2018-04-15 14:15:00    1012       20.0    87
           2018-04-15 14:45:00    1013       20.0    87
           2018-04-15 15:15:00    1012       21.0    87
           2018-04-15 15:45:00    1014       22.0    86
           2018-04-15 16:00:00    1015       22.0    86
           2018-04-15 16:01:00    1012       25.0    86
           2018-04-15 16:02:00    1012       25.0    86
Stratford  2018-04-15 14:15:00    1011       18.0    87
           2018-04-15 14:45:00    1011       18.0    87
           2018-04-15 15:15:00    1012       18.0    87
           2018-04-15 15:45:00    1014       19.0    86
           2018-04-15 16:00:00    1014       19.0    86
           2018-04-15 16:01:00    1015       19.0    86
           2018-04-15 16:02:00    1016       20.0    86
           2018-04-15 16:04:00    1016       20.0    86

请注意,观测值的抽样从过去 :15 和 :45 的每 30 分钟到每分钟(例如 :01、:02、:14 等)不等,而且也因站而异 - 并非所有站都有每次观察。

我试过了:

weather_test = weather.resample('30min', level=1).mean()

但这会在没有偏移的情况下重新采样,并且还摆脱了多索引中的站点级别。

想要的结果是这样的:

                              Pressure   Temp    Hum
Station    parsed_time
Bow            2018-04-15 14:15:00    1012       20.0    87
           2018-04-15 14:45:00    1013       20.0    87
           2018-04-15 15:15:00    1012       21.0    87
           2018-04-15 15:45:00    1014       22.0    86
           2018-04-15 16:15:00    1013       24.0    86
Stratford  2018-04-15 14:15:00    1011       18.0    87
           2018-04-15 14:45:00    1011       18.0    87
           2018-04-15 15:15:00    1012       18.0    87
           2018-04-15 15:45:00    1014       19.0    86
           2018-04-15 16:15:00    1015       19.5    86

每分钟的观测值已被重新采样为 30 分钟间隔内的平均值,时间为每小时 15 分和 45 分。

将站点作为多索引中的一个级别是必不可少的。我不能单独使用时间索引作为索引,因为每个站点的值都重复(并且不是唯一的)。

感谢所有帮助,因为我已经在这个圈子里转了一段时间。谢谢!

我看过很多以前的帖子,包括: Boolean filter using a timestamp value on a dataframe in PythonHow do I round datetime column to nearest quarter hour 和:Resampling a pandas dataframe with multi-index containing timeseries 对于应该很简单的事情来说,这似乎有点复杂......

和文档:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.resample.html 谢谢!

【问题讨论】:

【参考方案1】:

我没有您的数据,因此无法直接检查,但请尝试以下语法用于您称为选项 1 的选项:

weather_test = weather[(weather['parsed_time'].dt.minute == 15) | (weather['parsed_time'].dt.minute == 45)]

【讨论】:

感谢@BossaNova - 修复了选项 1,但我仍然对能够重新采样不等间隔的数据点非常感兴趣【参考方案2】:

从倒数第二个数据帧开始(使用weather.reset_index(Station, inplace=True) 之后):

                           Station  Pressure  Temp   Hum
parsed_time                                         
2018-04-15 14:15:00        Bow    1012.0  20.0  87.0
2018-04-15 14:45:00        Bow    1013.0  20.0  87.0
2018-04-15 15:15:00        Bow    1012.0  21.0  87.0
2018-04-15 15:45:00        Bow    1014.0  22.0  86.0
2018-04-15 16:00:00        Bow    1015.0  22.0  86.0
2018-04-15 16:01:00        Bow    1012.0  25.0  86.0
2018-04-15 16:02:00        Bow    1012.0  25.0  86.0
2018-04-15 14:15:00  Stratford    1011.0  18.0  87.0
2018-04-15 14:45:00  Stratford    1011.0  18.0  87.0
2018-04-15 15:15:00  Stratford    1012.0  18.0  87.0
2018-04-15 15:45:00  Stratford    1014.0  19.0  86.0
2018-04-15 16:00:00  Stratford    1014.0  19.0  86.0
2018-04-15 16:01:00  Stratford    1015.0  19.0  86.0
2018-04-15 16:02:00  Stratford    1016.0  20.0  86.0
2018-04-15 16:04:00  Stratford    1016.0  20.0  86.0

您可以使用groupbyresample 的组合:

res = weather.groupby('Station').resample('30min').mean().reset_index('Station')

默认情况下,resample 选择 bin 间隔 [16:00, 16:30)[16:30, 17:00)。正如您已经注意到的,时间索引是在没有偏移的情况下重新采样的,但是您可以在之后使用 DateOffset 将其添加回来:

res.index = res.index + pd.DateOffset(minutes=15)

产生:

                           Station  Pressure  Temp   Hum
parsed_time                                         
2018-04-15 14:15:00        Bow   1012.00  20.0  87.0
2018-04-15 14:45:00        Bow   1013.00  20.0  87.0
2018-04-15 15:15:00        Bow   1012.00  21.0  87.0
2018-04-15 15:45:00        Bow   1014.00  22.0  86.0
2018-04-15 16:15:00        Bow   1013.00  24.0  86.0
2018-04-15 14:15:00  Stratford   1011.00  18.0  87.0
2018-04-15 14:45:00  Stratford   1011.00  18.0  87.0
2018-04-15 15:15:00  Stratford   1012.00  18.0  87.0
2018-04-15 15:45:00  Stratford   1014.00  19.0  86.0
2018-04-15 16:15:00  Stratford   1015.25  19.5  86.0

或者,您可以直接在重采样方法中指定偏移量:

weather.groupby('Station').resample('30min', loffset=pd.Timedelta('15min')).mean()

【讨论】:

谢谢,效果很好!为了更清楚,我唯一要添加的是reset_index('Station'),我相信您的意思是reset_index('Station', append=True, inplace=True),它将站点添加为列而不是索引的一部分。这是正确的吗? 是的,没错。我认为,append=True 是不必要的。【参考方案3】:

如果开始时没有任何索引(行索引除外),则可以执行以下操作:

# Create a rounded timestamp
df['parsed_time_rounded'] = (df['parsed_time'] - pd.Timedelta('15min')).dt.round('30min') + pd.Timedelta('15min')
# Group by the station, and the rounded timestamp instead of the raw timestamp
df.groupby(['Station', 'parsed_time_rounded']).mean()

【讨论】:

感谢 PMende - 这实际上对于在另一个数据帧中舍入时间戳以匹配气象站格式非常有用,并且实际上是这个问题的完美答案,我也仔细阅读了:***.com/questions/49575973/…跨度>

以上是关于Pandas 将时间序列数据重新采样为 15 分钟和 45 分钟 - 使用多索引或列的主要内容,如果未能解决你的问题,请参考以下文章

Pandas 将 5 分钟数据重新采样为每小时平均值:日期问题 [重复]

无法从 1 分钟到 5 分钟的数据重新采样 pandas 时间序列

如何在 Pandas/Numpy 中使用 dateOffset 对日内时间序列数据进行重新采样?

pandas OHLC 聚合随着 OHLC 的时间重新采样

pandas的resample重采样

如何将 pandas Dataframe 时间序列数据从 8hz 重新采样到 16hz?