2013-08-12 10 views
9

Se ho un pandas.core.series.Series nome ts di entrambi 1 del o NaN di come questo:cumSum ripristinare al NaN

3382 NaN 
3381 NaN 
... 
3369 NaN 
3368 NaN 
... 
15  1 
10 NaN 
11  1 
12  1 
13  1 
9 NaN 
8 NaN 
7 NaN 
6 NaN 
3 NaN 
4  1 
5  1 
2 NaN 
1 NaN 
0 NaN 

Vorrei calcolare cumSum di questa serie ma dovrebbe essere ripristinato (azzeramento) al posizione dei NaN come di seguito:

3382 0 
3381 0 
... 
3369 0 
3368 0 
... 
15  1 
10  0 
11  1 
12  2 
13  3 
9  0 
8  0 
7  0 
6  0 
3  0 
4  1 
5  2 
2  0 
1  0 
0  0 

Idealmente mi piacerebbe avere una soluzione vettoriale!

ho mai visto una domanda simile con Matlab: Matlab cumsum reset at NaN?

ma non so come tradurre questa linea d = diff([0 c(n)]);

risposta

7

una semplice traduzione Numpy del codice Matlab è questo:

import numpy as np 

v = np.array([1., 1., 1., np.nan, 1., 1., 1., 1., np.nan, 1.]) 
n = np.isnan(v) 
a = ~n 
c = np.cumsum(a) 
d = np.diff(np.concatenate(([0.], c[n]))) 
v[n] = -d 
np.cumsum(v) 

L'esecuzione di questo codice restituisce il risultato array([ 1., 2., 3., 0., 1., 2., 3., 4., 0., 1.]). Questa soluzione sarà valida solo come quella originale, ma forse ti aiuterà a trovare qualcosa di meglio se non è sufficiente per i tuoi scopi.

9

Ecco un panda-onic modo un po 'più per farlo:

v = Series([1, 1, 1, nan, 1, 1, 1, 1, nan, 1], dtype=float) 
n = v.isnull() 
a = ~n 
c = a.cumsum() 
index = c[n].index # need the index for reconstruction after the np.diff 
d = Series(np.diff(np.hstack(([0.], c[n]))), index=index) 
v[n] = -d 
result = v.cumsum() 

nota che uno di questi richiede che si sta utilizzando pandas almeno 9da899b o più recente. Se non sei allora si può lanciare il booldtype a un int64 o float64dtype:

v = Series([1, 1, 1, nan, 1, 1, 1, 1, nan, 1], dtype=float) 
n = v.isnull() 
a = ~n 
c = a.astype(float).cumsum() 
index = c[n].index # need the index for reconstruction after the np.diff 
d = Series(np.diff(np.hstack(([0.], c[n]))), index=index) 
v[n] = -d 
result = v.cumsum() 
+0

'ValueError: non può convertire float NaN a integer' per 'ts.notnull.cumsum()' su panda 0.12. Non sono sicuro del motivo per cui ciò si verificherebbe per una serie booleana .. – machow

+0

Che avrebbe dovuto essere corretto da ['9da899b'] (https://github.com/pydata/pandas/commit/9da899ba3d1099d7456adb32ea129547f152dee8) –

+0

@Closed Assicurati sei aggiornato e fammi sapere se non funziona ancora. –

2

Se si può accettare un simile booleano Serie b, tenta

(b.cumsum() - b.cumsum().where(~b).fillna(method='pad').fillna(0)).astype(int) 

A partire dal Series ts, b = (ts == 1) o b = ~ts.isnull().

4

Ancora più panda-onic modo per farlo:

v = pd.Series([1., 3., 1., np.nan, 1., 1., 1., 1., np.nan, 1.]) 
cumsum = v.cumsum().fillna(method='pad') 
reset = -cumsum[v.isnull()].diff().fillna(cumsum) 
result = v.where(v.notnull(), reset).cumsum() 

Contrariamente al codice MATLAB, questo funziona anche per valori diversi da 1.