Python Pandas cumsum com deslocamento de n

Oct 01 2020

Gostaria de saber se existe uma maneira eficiente (evitando loops for) de fazer a, serie.cumsum()mas com um deslocamento de n .

Da mesma forma que você pode ver serie.cumsum()o inverso de serie.diff(1)Estou procurando o inverso de diff(n)(eu sei que para um inverso adequado você precisa dos valores iniciais, mas para simplificar eu os ignoro aqui) que poderia ser chamadocumsum_shift

Implementando-o mais explicitamente com um loop for (que eu gostaria de evitar):

def cumsum_shift(s, shift = 1, init_values = [0]):
    s_cumsum = pd.Series(np.zeros(len(s)))
    for i in range(shift):
        s_cumsum.iloc[i] = init_values[i]
    for i in range(shift,len(s)):
        s_cumsum.iloc[i] = s_cumsum.iloc[i-shift] + s.iloc[i]
    return s_cumsum

Este código com shift = 1é exatamente o mesmo que o s.cumsum()método pandas, mas é claro que o método pandas o faz em código C (eu acho), então é muito mais rápido (claro que você deve sempre usar o s.cumsum()método pandas e não implementá-lo sozinho com um for ciclo).

Minha pergunta então é: Qual seria a maneira de cumsum_shiftevitar um loop for com os métodos do pandas?

Editar 1

Adicionando um exemplo de entrada e saída

Se você ligar com:

s = pd.Series([1,10,100,2,20,200,5,50,500])
s.diff(3)
out[26] 0      NaN
        1      NaN
        2      NaN
        3      1.0
        4     10.0
        5    100.0
        6      3.0
        7     30.0
        8    300.0
        dtype: float64

Com esta entrada, a saída de cumsum_shift(s.diff(3), shift = 3, init_values = [1,2,3])é novamente a série original s. Observe a mudança de 3, isso com apenas cumsum()por exemplo s.diff(3).cumsum(), não recuperaria o original s:

cumsum_shift(s.diff(3), shift = 3, init_values= [1,10,100])
out[27]
0      1.0
1     10.0
2    100.0
3      2.0
4     20.0
5    200.0
6      5.0
7     50.0
8    500.0
dtype: float64

Mas deixe-me enfatizar que os valores iniciais não são um grande problema, uma diferença constante não é um problema. Eu gostaria de saber como realizar um cumsum de serie diferenciada deslocada sem ter que usar um loop for

Da mesma forma que se você fizer um diff()e depois um, cumsum()você retorna o original até o valor inicial:

s = pd.Series([1,10,100,2,20,200,5,50,500])
s.diff().cumsum()
out[28]
0      NaN
1      9.0
2     99.0
3      1.0
4     19.0
5    199.0
6      4.0
7     49.0
8    499.0
dtype: float64

Gostaria de saber se há alguma maneira inteligente de fazer algo assim s.diff(n).cumsum(n)retornou algo correto até alguns valores iniciais constantes.

EDIT 2 - Reverter uma média móvel

Pensando em uma aplicação do "cumsum deslocado", encontrei esta outra pergunta no SO de como reverter uma média móvel que respondi usando minha cumsum_shiftfunção e acho que esclarece mais o que estou perguntando aqui

Respostas

1 Elif Oct 01 2020 at 21:34

Você pode usar o método pandas rolling.sum () entre com sum:

s.rolling(shift).sum()

No entanto, você pode querer preencher os valores NaN até a mudança com o df original.