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:00
2018-04-15 15:13:00
weather_test = weather[weather['parsed_time'].dt.minute == (15 | 45)]
产生如下 parsed_time 值:
2018-04-15 14:47:00
2018-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
您可以使用groupby
和resample
的组合:
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 时间序列