熊猫时间序列重采样和插值一起

Posted

技术标签:

【中文标题】熊猫时间序列重采样和插值一起【英文标题】:Pandas timeseries resampling and interpolating together 【发布时间】:2017-02-23 08:20:12 【问题描述】:

我有带时间戳的传感器数据。由于技术细节的原因,我以大约一分钟的间隔从传感器获取数据。数据可能如下所示:

   tstamp               val
0  2016-09-01 00:00:00  57
1  2016-09-01 00:01:00  57
2  2016-09-01 00:02:23  57
3  2016-09-01 00:03:04  57
4  2016-09-01 00:03:58  58
5  2016-09-01 00:05:00  60

现在,基本上,如果我能在准确的时间获得所有数据,我会非常高兴,但我没有。保存分布和每分钟都有数据的唯一方法是插值。例如,行索引 1 和 2 之间有 83 秒,而在精确分钟获取值的自然方法是在两行数据之间进行插值(在本例中为 57,但事实并非如此无处不在)。

现在,我的方法是执行以下操作:

date = pd.to_datetime(df['measurement_tstamp'].iloc[0].date())
ts_d = df['measurement_tstamp'].dt.hour * 60 * 60 +\
       df['measurement_tstamp'].dt.minute * 60 +\
       df['measurement_tstamp'].dt.second
ts_r = np.arange(0, 24*60*60, 60)
data = scipy.interpolate.interp1d(x=ts_d, y=df['speed'].values)(ts_r)
req = pd.Series(data, index=pd.to_timedelta(ts_r, unit='s'))
req.index = date + req.index

但这对我来说感觉相当冗长和漫长。有一些出色的 pandas 方法可以进行重采样、舍入等。我整天都在阅读它们,但事实证明,没有任何东西可以按照我想要的方式进行插值。 resamplegroupby 一样工作,平均时间点落在一起。 fillna 进行插值,但不是在 resample 已经通过平均改变数据之后。

是我遗漏了什么,还是我的方法是最好的?


为简单起见,假设我按天和传感器对数据进行分组,因此一次只插入来自一个传感器的 24 小时时段。

【问题讨论】:

【参考方案1】:
d = df.set_index('tstamp')
t = d.index
r = pd.date_range(t.min().date(), periods=24*60, freq='T')

d.reindex(t.union(r)).interpolate('index').ix[r]


注意,periods=24*60 适用于每日数据,而不是问题中提供的样本。对于该示例,periods=6 将起作用。

【讨论】:

但是resample 在同一组中出现两个或多个观察值时的平均值,不是吗? 所以,这个数据实际上遵循一个分布。本质上,我想要的是两点之间的线性插值,这样插值点正好落在一分钟。这种数据永远不会发生在一分钟内有超过 2 次观察的情况。事实上,大部分数据确实在精确的分钟内落下,但有时传感器会迟到或早点。通常,我的同事将它四舍五入到最接近的分钟,并用之前时间戳的值填充任何缺失的时间戳,但这会在一定程度上改变分布。我的问题需要更严格的约束。 不错!但是,您可以将此与我在问题中的解决方案进行比较吗?我有一个数据集(仅 9 月),大约有 1.14 亿条记录(2,655 个传感器,每天报告近 1440 个数据点)。我认为每秒插值会导致它变慢。 是的,我一直在努力解决这个问题……还在思考。 我想我必须对我的解决方案感到满意。这已经足够好了。在 6 M 行的数据集上,只用了 20.5 秒(部分归功于 groupby().apply 释放 GIL)...【参考方案2】:

5 年后,pandas 发生了一些变化(大部分 ix 函数已弃用)。无论如何,我已经重写了 piRSquared 的答案以使用当前的 pandas 版本,并且还改进了答案的日期范围问题:

import pandas as pd
from datetime import datetime

df = pd.DataFrame("tstamp": [
    datetime(2016, 9, 1, 0, 0, 0),
    datetime(2016, 9, 1, 0, 1, 0),
    datetime(2016, 9, 1, 0, 2, 23),
    datetime(2016, 9, 1, 0, 3, 4),
    datetime(2016, 9, 1, 0, 3, 58),
    datetime(2016, 9, 1, 0, 5, 0)], 
    "val": [57, 57, 57, 57, 58, 60])


d = df.set_index('tstamp')
t = d.index

r = pd.date_range(t.min(), t.max(), freq='T')

d = d.reindex(t.union(r)).interpolate('index').loc[r]

d:

                           val
2016-09-01 00:00:00  57.000000
2016-09-01 00:01:00  57.000000
2016-09-01 00:02:00  57.000000
2016-09-01 00:03:00  57.000000
2016-09-01 00:04:00  58.064516
2016-09-01 00:05:00  60.000000

【讨论】:

以上是关于熊猫时间序列重采样和插值一起的主要内容,如果未能解决你的问题,请参考以下文章

熊猫结合了滚动和重采样

使用重采样来对齐熊猫中的多个时间序列

如何理解熊猫重采样方法中的封闭和标签参数?

时间序列重采样错误 - 熊猫列中没有日期索引

重采样后合并熊猫数据帧

基于列标准的熊猫数据框重采样