Decaimiento exponencial en el dataframe de Python Pandas

Estoy tratando de calcular de manera eficiente una sum stream, con decaimiento exponencial, de cada columna de un Pandas DataFrame. El DataFrame contiene una puntuación diaria para cada país en el mundo. El DataFrame se ve así:

AF UK US 2014-07-01 0.998042 0.595720 0.524698 2014-07-02 0.380649 0.838436 0.355149 2014-07-03 0.306240 0.274755 0.964524 2014-07-04 0.396721 0.836027 0.225848 2014-07-05 0.151291 0.677794 0.603548 2014-07-06 0.558846 0.050535 0.551785 2014-07-07 0.463514 0.552748 0.265537 2014-07-08 0.240282 0.278825 0.116432 2014-07-09 0.309446 0.096573 0.246021 2014-07-10 0.800977 0.583496 0.713893 

No estoy seguro de cómo calcular la sum móvil (con disminución) sin iterar a través del dataframe, ya que necesito saber la puntuación de ayer para calcular la puntuación de hoy. Pero para calcular el puntaje de ayer, necesito saber el día anterior al de ayer, etc. Este es el código que he estado usando, pero me gustaría una manera más eficiente de hacerlo.

 for j, val in df.iteritems(): for i, row in enumerate(val): df[j].iloc[i] = row + val[i-1]*np.exp(-0.05) 

Puede usar el hecho de que cuando los exponenciales multiplican sus exponentes se agregan:

p.ej:

 N(2) = N(2) + N(1) * exp(-0.05) N(3) = N(3) + (N(2) + N(1) * exp(-0.05))*exp(-0.05) N(3) = N(3) + N(2)*exp(-0.05) + N(1)*exp(-0.1) N(4) = ...and so on 

Esto puede ser vectorizado usando numpy:

 dataset = pd.DataFrame(np.random.rand(1000,3), columns=["A", "B","C"]) weightspace = np.exp(np.linspace(len(dataset), 0, num=len(dataset))*-0.05) def rollingsum(array): weights = weightspace[0-len(array):] # Convolve the array and the weights to obtain the result a = np.dot(array, weights).sum() return a a = pd.expanding_apply(dataset, rollingsum) 

pd.expanding_apply aplica la función rollingsum hacia atrás a cada fila, llamándola len(dataset) veces. np.linspace genera un conjunto de datos de tamaño len(dataset) y calcula cuántas veces se multiplica cada fila por exp(-0.05) para la fila actual.

Debido a que está vectorizado, debe ser rápido:

 %timeit a = pd.expanding_apply(dataset, rollingsum) 10 loops, best of 3: 25.5 ms per loop 

Esto se compara con (nota que estoy usando python 3 y tuve que hacer un cambio en el comportamiento en la primera fila …):

 def multipleApply(df): for j, val in df.iteritems(): for i, row in enumerate(val): if i == 0: continue df[j].iloc[i] = row + val[i-1]*np.exp(-0.05) 

Esto sale como:

 In[68]: %timeit multipleApply(dataset) 1 loops, best of 3: 414 ms per loop