Pandas Rolling Computations en ventanas corredizas (espaciadas de manera desigual)

Considera que tienes algunos datos de series de tiempo desiguales:

import pandas as pd import random as randy ts = pd.Series(range(1000),index=randy.sample(pd.date_range('2013-02-01 09:00:00.000000',periods=1e6,freq='U'),1000)).sort_index() print ts.head() 2013-02-01 09:00:00.002895 995 2013-02-01 09:00:00.003765 499 2013-02-01 09:00:00.003838 797 2013-02-01 09:00:00.004727 295 2013-02-01 09:00:00.006287 253 

Digamos que quería hacer la sum móvil en una ventana de 1 ms para obtener esto:

 2013-02-01 09:00:00.002895 995 2013-02-01 09:00:00.003765 499 + 995 2013-02-01 09:00:00.003838 797 + 499 + 995 2013-02-01 09:00:00.004727 295 + 797 + 499 2013-02-01 09:00:00.006287 253 

Actualmente, hago que todo vuelva a ser largo y lo haga en cython, pero ¿es esto posible en pandas puros? Soy consciente de que puedes hacer algo como .asfreq (‘U’) y luego llenar y usar las funciones tradicionales, pero esto no se puede escalar una vez que tienes más de un juguete # de filas.

Como punto de referencia, aquí hay una versión de Cython pirateada, no rápida:

 %%cython import numpy as np cimport cython cimport numpy as np ctypedef np.double_t DTYPE_t def rolling_sum_cython(np.ndarray[long,ndim=1] times, np.ndarray[double,ndim=1] to_add, long window_size): cdef long t_len = times.shape[0], s_len = to_add.shape[0], i =0, win_size = window_size, t_diff, j, window_start cdef np.ndarray[DTYPE_t, ndim=1] res = np.zeros(t_len, dtype=np.double) assert(t_len==s_len) for i in range(0,t_len): window_start = times[i] - win_size j = i while times[j]>= window_start and j>=0: res[i] += to_add[j] j-=1 return res 

Demostrando esto en una serie ligeramente más grande:

 ts = pd.Series(range(100000),index=randy.sample(pd.date_range('2013-02-01 09:00:00.000000',periods=1e8,freq='U'),100000)).sort_index() %%timeit res2 = rolling_sum_cython(ts.index.astype(int64),ts.values.astype(double),long(1e6)) 1000 loops, best of 3: 1.56 ms per loop 

Puede resolver la mayoría de los problemas de este tipo con la búsqueda acumulada y binaria.

 from datetime import timedelta def msum(s, lag_in_ms): lag = s.index - timedelta(milliseconds=lag_in_ms) inds = np.searchsorted(s.index.astype(np.int64), lag.astype(np.int64)) cs = s.cumsum() return pd.Series(cs.values - cs[inds].values + s[inds].values, index=s.index) res = msum(ts, 100) print pd.DataFrame({'a': ts, 'a_msum_100': res}) a a_msum_100 2013-02-01 09:00:00.073479 5 5 2013-02-01 09:00:00.083717 8 13 2013-02-01 09:00:00.162707 1 14 2013-02-01 09:00:00.171809 6 20 2013-02-01 09:00:00.240111 7 14 2013-02-01 09:00:00.258455 0 14 2013-02-01 09:00:00.336564 2 9 2013-02-01 09:00:00.536416 3 3 2013-02-01 09:00:00.632439 4 7 2013-02-01 09:00:00.789746 9 9 [10 rows x 2 columns] 

Necesita una forma de manejar los NaN y, dependiendo de su aplicación, puede necesitar el valor prevaleciente o no del tiempo retrasado (es decir, la diferencia entre el uso de kdb + bin vs np.searchsorted).

Espero que esto ayude.

Esta es una pregunta antigua, pero para aquellos que se topan con esto desde google: en pandas 0.19, esta función está incorporada

http://pandas.pydata.org/pandas-docs/stable/computation.html#time-aware-rolling

Así que para obtener ventanas de 1 ms parece que obtienes un objeto Rolling haciendo

 dft.rolling('1ms') 

y la sum seria

 dft.rolling('1ms').sum() 

Quizás tenga más sentido usar rolling_sum :

 pd.rolling_sum(ts, window=1, freq='1ms') 

Qué tal algo como esto:

Crea un offset para 1 ms:

 In [1]: ms = tseries.offsets.Milli() 

Cree una serie de posiciones de índice de la misma longitud que su serie temporal:

 In [2]: s = Series(range(len(ts))) 

Aplique una función lambda que indexe la hora actual de la serie ts. La función devuelve la sum de todas las entradas ts entre x - ms and x .

 In [3]: s.apply(lambda x: ts.between_time(start_time=ts.index[x]-ms, end_time=ts.index[x]).sum()) In [4]: ts.head() Out[4]: 2013-02-01 09:00:00.000558 348 2013-02-01 09:00:00.000647 361 2013-02-01 09:00:00.000726 312 2013-02-01 09:00:00.001012 550 2013-02-01 09:00:00.002208 758 

Resultados de la función anterior:

 0 348 1 709 2 1021 3 1571 4 758