Python упорядочивает нерегулярные временные ряды с линейной интерполяцией
У меня есть временной ряд в pandas, который выглядит так:
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')) из pandas, я получаю:
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", но не получил точно тех результатов, которые я хотел. Я использую неправильный метод?
Я считаю, что это довольно простой запрос, но я некоторое время искал веб-сайт и не нашел ответа.
Заранее благодарим за любую помощь, которую я могу получить.
Ответы
Ответ 1
Требуется немного работы, но попробуйте это. Основная идея - найти ближайшие две метки времени для каждой точки повторной выборки и интерполировать. 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
Ответ 2
Вы можете сделать это с помощью traces. Во-первых, создайте 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',
)
Это приводит к следующей регуляризованной версии, где серые точки - это исходные данные, а оранжевый - регуляризованная версия с линейной интерполяцией.
![временные ряды с линейной интерполяцией]()
Интерполированные значения:
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
Ответ 3
Тот же результат, который получает @mstringer, может быть достигнут исключительно в pandas. Фокус в том, чтобы сначала выполнить повторную выборку на второй, используя интерполяцию, чтобы заполнить промежуточные значения (.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
Ответ 4
Недавно мне пришлось перепрограммировать данные ускорения, которые были неравномерно отобраны. Он обычно выбирался с правильной частотой, но с задержкой, периодически накапливаемой.
Я нашел этот вопрос и комбинировал 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, и этот метод работает с DataFrames (это то, что я изначально использовал для него). Наконец, обратите внимание, что интерполяция по умолчанию применяется к "линейному" методу, который игнорирует информацию о времени в индексе и не будет работать с неравномерно распределенными данными.