Python regulariza series temporales irregulares con interpolación lineal.

Tengo una serie de tiempo en pandas que se ve así:

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 

Me gustaría volver a muestrearlo en una serie de tiempo regular con pasos de 15 minutos donde los valores se interpolan linealmente. Básicamente me gustaría conseguir:

  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 

Sin embargo, utilizando el método de remuestreo (df.resample (’15Min’)) de Pandas obtengo:

  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 

He probado el método de remuestreo con diferentes parámetros de ‘cómo’ y ‘método de relleno’, pero nunca obtuve exactamente los resultados que quería. ¿Estoy usando el método equivocado?

Me imagino que esta es una consulta bastante simple, pero he buscado en la web por un tiempo y no pude encontrar una respuesta.

Gracias de antemano por cualquier ayuda que pueda obtener.

Se necesita un poco de trabajo, pero prueba esto. La idea básica es encontrar las dos marcas de tiempo más cercanas a cada punto de remuestreo e interpolar. np.searchsorted se utiliza para buscar fechas más cercanas al punto de remuestreo.

 # 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') 

Después de todo eso, esperemos que la respuesta correcta:

 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 

Puedes hacer esto con trazas . Primero, cree un TimeSeries con sus medidas irregulares como lo haría con un diccionario:

 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), ]) 

Luego regularizar usando el método de sample :

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

Esto da como resultado la siguiente versión regularizada, donde los puntos grises son los datos originales y la naranja es la versión regularizada con interpolación lineal.

Series de tiempo con interpolación lineal.

Los valores interpolados son:

 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 

El mismo resultado que obtiene @mstringer puede lograrse únicamente en pandas. El truco consiste en volver a muestrear por segundo, utilizando la interpolación para completar los valores intermedios ( .resample('s').interpolate() ), y luego muestrear en períodos de 15 minutos ( .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) 

Salida:

 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 

Hace poco tuve que volver a muestrear datos de aceleración que no fueron muestreados uniformemente. En general, se tomaron muestras en la frecuencia correcta, pero tuvieron retrasos intermitentes que se acumularon.

Encontré esta pregunta y combiné las respuestas de mstringer y Alberto Garcia-Rabosco usando pandas puros y adormecidos. Este método crea un nuevo índice a la frecuencia deseada y luego se interpola sin el paso intermitente de interpolar a una frecuencia más alta.

 # 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) 

Código para hacer la interpolación:

 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) 

Salida:

 >>> 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 

Como antes, puede usar cualquier método de interpolación que admita Scipy y esta técnica también funciona con DataFrames (para eso lo usé originalmente). Finalmente, tenga en cuenta que interpolar los valores predeterminados al método ‘lineal’ que ignora la información de tiempo en el índice y no funcionará con datos espaciados de manera no uniforme.