Python упорядочивает нерегулярные временные ряды с линейной интерполяцией

у меня есть временной ряд в панд, который выглядит так:

                     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

однако с помощью метода resample (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  

Я пробовал метод resample с различными параметрами "как" и "fill_method", но никогда не получал точно результатов I желаемый. Я использую неправильный метод?

Я думаю, это довольно простой запрос, но я искал в интернете и не мог найти ответ.

заранее спасибо за любую помощь я могу получить.

4 ответов


это требует немного работы,но попробуйте это. Основная идея-найти ближайшие две временные метки для каждой точки повторной выборки и интерполировать. 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

вы можете сделать это с помощью следы. Во-первых, создать 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 способ:

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

это приводит к следующей регуляризованной версии, где серые точки являются исходными данными, а оранжевый-регуляризованной версией с линейной интерполяцией.

time series with linear interpolation

интерполированные значения являются:

1992-08-27 08:00:00    28.189 
1992-08-27 08:15:00    28.286  
1992-08-27 08:30:00    28.377
1992-08-27 08:45:00    28.848
1992-08-27 09:00:00    29.891

тот же результат, который получает @mstringer, может быть достигнут исключительно в панд. Хитрость заключается в том, чтобы сначала пересчитать по секундам, используя интерполяцию для заполнения промежуточных значений (.resample('s').interpolate()), а затем upsample в 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

недавно мне пришлось повторно сравнить данные ускорения, которые были неравномерно отобраны. Как правило, он отбирался с правильной частотой,но с периодическими задержками, которые накапливались.

Я нашел этот вопрос и объединил ответы mstringer и Alberto Garcia-Rabosco, используя чистых панд и numpy. Этот метод создает новый индекс на нужной частоте, а затем интерполирует без прерывистого шага интерполяции на более высокой частоте.

# 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, и этот метод также работает с фреймами данных (это то, для чего я изначально его использовал). Наконец, отметим, что интерполяция по умолчанию "линейный" метод, который игнорирует информацию о времени в индексе и не будет работать с неравномерно распределенных данных.