Pandas 时间序列重采样和插值一起
Pandas timeseries resampling and interpolating together
我有带时间戳的传感器数据。由于技术细节,我以 大约 一分钟的间隔从传感器获取数据。数据可能如下所示:
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 方法可以执行重采样、舍入等操作。我整天都在阅读它们,但事实证明,没有任何方法可以按照我想要的方式进行插值。 resample
的工作方式类似于 groupby
,并对落在一起的时间点进行平均。 fillna
进行插值,但在 resample
已经通过平均改变了数据之后。
我是不是遗漏了什么,或者我的方法是最好的吗?
为简单起见,假设我按天和传感器对数据进行分组,因此一次仅插入来自一个传感器的 24 小时周期。
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
将起作用。
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
我有带时间戳的传感器数据。由于技术细节,我以 大约 一分钟的间隔从传感器获取数据。数据可能如下所示:
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 方法可以执行重采样、舍入等操作。我整天都在阅读它们,但事实证明,没有任何方法可以按照我想要的方式进行插值。 resample
的工作方式类似于 groupby
,并对落在一起的时间点进行平均。 fillna
进行插值,但在 resample
已经通过平均改变了数据之后。
我是不是遗漏了什么,或者我的方法是最好的吗?
为简单起见,假设我按天和传感器对数据进行分组,因此一次仅插入来自一个传感器的 24 小时周期。
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
将起作用。
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