熊猫使用多索引或列将时间序列数据重采样到15分钟和45分钟

时间:2018-08-06 10:30:01

标签: python pandas dataframe time-series multi-index

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

我想到了两种实现方法。
1.使用时间序列数据作为数据框中的一列,只需在15min和45min时对所有观察数据进行过滤即可。
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:30和过去的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 Python
How 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 谢谢!

3 个答案:

答案 0 :(得分: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选择合并间隔[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()

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

# 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()