Python使用线性插值来规范不规则时间序列

时间:2014-08-11 02:04:51

标签: python pandas time-series linear-interpolation

我在熊猫中有一个时间序列,如下所示:

                     Values
1992-08-27 07:46:48    28.0  
1992-08-27 08:00:48    28.2  
1992-08-27 08:33:48    28.4  
1992-08-27 08:43:48    28.8  
1992-08-27 08:48:48    29.0  
1992-08-27 08:51:48    29.2  
1992-08-27 08:53:48    29.6  
1992-08-27 08:56:48    29.8  
1992-08-27 09:03:48    30.0

我想将其重新采样到一个常规时间序列,步长为15分钟,其中值是线性插值的。基本上我想得到:

                     Values
1992-08-27 08:00:00    28.2  
1992-08-27 08:15:00    28.3  
1992-08-27 08:30:00    28.4  
1992-08-27 08:45:00    28.8  
1992-08-27 09:00:00    29.9

然而,使用来自Pandas的重新采样方法(df.resample('15Min')),我得到:

                     Values
1992-08-27 08:00:00   28.20  
1992-08-27 08:15:00     NaN  
1992-08-27 08:30:00   28.60  
1992-08-27 08:45:00   29.40  
1992-08-27 09:00:00   30.00  

我尝试了不同的'how'和'fill_method'参数的重采样方法,但从未得到我想要的结果。我使用了错误的方法吗?

我认为这是一个相当简单的查询,但我在网上搜索了一段时间,却找不到答案。

提前感谢您提供的任何帮助。

4 个答案:

答案 0 :(得分:12)

您可以使用traces执行此操作。首先,使用不规则的测量值创建def convert(s): beginning = "" index = 0; for char in s: if char in ('a','e','i','o','u'): end = str(s[index:]) break else: beginning = beginning + char index = index + 1 return str(end) + "-" + beginning + "ay" ,就像字典一样:

TimeSeries

然后使用ts = traces.TimeSeries([ (datetime(1992, 8, 27, 7, 46, 48), 28.0), (datetime(1992, 8, 27, 8, 0, 48), 28.2), ... (datetime(1992, 8, 27, 9, 3, 48), 30.0), ]) 方法进行规范化:

sample

这导致以下正则化版本,其中灰点是原始数据,橙色是带线性插值的正则化版本。

time series with linear interpolation

插值是:

ts.sample(
    sampling_period=timedelta(minutes=15),
    start=datetime(1992, 8, 27, 8),
    end=datetime(1992, 8, 27, 9),
    interpolate='linear',
)

答案 1 :(得分:7)

@mstringer得到的结果可以纯粹在熊猫中实现。诀窍是先按秒重新采样,使用插值填充中间值(.resample('s').interpolate()),然后在15分钟内(.resample('15T').asfreq())进行上采样。

import io
import pandas as pd

data = io.StringIO('''\
Values
1992-08-27 07:46:48,28.0  
1992-08-27 08:00:48,28.2  
1992-08-27 08:33:48,28.4  
1992-08-27 08:43:48,28.8  
1992-08-27 08:48:48,29.0  
1992-08-27 08:51:48,29.2  
1992-08-27 08:53:48,29.6  
1992-08-27 08:56:48,29.8  
1992-08-27 09:03:48,30.0
''')
s = pd.read_csv(data, squeeze=True)
s.index = pd.to_datetime(s.index)

res = s.resample('s').interpolate().resample('15T').asfreq().dropna()
print(res)

输出:

1992-08-27 08:00:00    28.188571
1992-08-27 08:15:00    28.286061
1992-08-27 08:30:00    28.376970
1992-08-27 08:45:00    28.848000
1992-08-27 09:00:00    29.891429
Freq: 15T, Name: Values, dtype: float64

答案 2 :(得分:5)

这需要一些工作,但试试这个。基本思路是找到每个重采样点最接近的两个时间戳并进行插值。 np.searchsorted用于查找最接近重采样点的日期。

# empty frame with desired index
rs = pd.DataFrame(index=df.resample('15min').iloc[1:].index)

# array of indexes corresponding with closest timestamp after resample
idx_after = np.searchsorted(df.index.values, rs.index.values)

# values and timestamp before/after resample
rs['after'] = df.loc[df.index[idx_after], 'Values'].values
rs['before'] = df.loc[df.index[idx_after - 1], 'Values'].values
rs['after_time'] = df.index[idx_after]
rs['before_time'] = df.index[idx_after - 1]

#calculate new weighted value
rs['span'] = (rs['after_time'] - rs['before_time'])
rs['after_weight'] = (rs['after_time'] - rs.index) / rs['span']
# I got errors here unless I turn the index to a series
rs['before_weight'] = (pd.Series(data=rs.index, index=rs.index) - rs['before_time']) / rs['span']

rs['Values'] = rs.eval('before * before_weight + after * after_weight')

毕竟,希望是正确答案:

In [161]: rs['Values']
Out[161]: 
1992-08-27 08:00:00    28.011429
1992-08-27 08:15:00    28.313939
1992-08-27 08:30:00    28.223030
1992-08-27 08:45:00    28.952000
1992-08-27 09:00:00    29.908571
Freq: 15T, Name: Values, dtype: float64

答案 3 :(得分:0)

我最近不得不重新采样非均匀采样的加速度数据。通常以正确的频率对其进行采样,但会间歇地延迟累积的延迟。

我找到了这个问题,并使用纯熊猫和numpy结合了mstringer和Alberto Garcia-Rabosco的答案。该方法以所需的频率创建一个新索引,然后进行插值,而无需执行以较高频率插值的间歇步骤。

# from Alberto Garcia-Rabosco above
import io
import pandas as pd

data = io.StringIO('''\
Values
1992-08-27 07:46:48,28.0  
1992-08-27 08:00:48,28.2  
1992-08-27 08:33:48,28.4  
1992-08-27 08:43:48,28.8  
1992-08-27 08:48:48,29.0  
1992-08-27 08:51:48,29.2  
1992-08-27 08:53:48,29.6  
1992-08-27 08:56:48,29.8  
1992-08-27 09:03:48,30.0
''')
s = pd.read_csv(data, squeeze=True)
s.index = pd.to_datetime(s.index)

执行插值的代码:

import numpy as np
# create the new index and a new series full of NaNs
new_index = pd.DatetimeIndex(start='1992-08-27 08:00:00', 
    freq='15 min', periods=5, yearfirst=True)
new_series = pd.Series(np.nan, index=new_index)

# concat the old and new series and remove duplicates (if any) 
comb_series = pd.concat([s, new_series])
comb_series = comb_series[~comb_series.index.duplicated(keep='first')]

# interpolate to fill the NaNs
comb_series.interpolate(method='time', inplace=True)

输出:

>>> print(comb_series[new_index])
1992-08-27 08:00:00    28.188571
1992-08-27 08:15:00    28.286061
1992-08-27 08:30:00    28.376970
1992-08-27 08:45:00    28.848000
1992-08-27 09:00:00    29.891429
Freq: 15T, dtype: float64

和以前一样,您可以使用scipy支持的任何插值方法,并且该技术也适用于DataFrames(这就是我最初使用的方法)。最后,请注意,插值默认为“线性”方法,该方法将忽略索引中的时间信息,并且不适用于间隔不均匀的数据。