2013-08-12 16 views
9

Wenn ich einen pandas.core.series.Seriests von entweder 1 oder des Nans wie folgt benannt haben:cumSum zurückgesetzt auf 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 

Ich würde cumsum dieser Serie berechnen möchten, aber es sollte zurückgesetzt werden (auf Null gesetzt) ​​bei der Position der NaNs wie unten:

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 

Idealerweise hätte ich gerne eine vektorisierte Lösung!

ich jemals eine ähnliche Frage mit Matlab sehen: Matlab cumsum reset at NaN?

aber ich weiß nicht, wie diese Zeile d = diff([0 c(n)]);

Antwort

7

Eine einfache Numpy Übersetzung Ihres Matlab-Code zu übersetzen, ist dies:

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) 

Die Ausführung dieses Codes gibt das Ergebnis array([ 1., 2., 3., 0., 1., 2., 3., 4., 0., 1.]) zurück. Diese Lösung wird nur so gut wie die ursprüngliche sein, aber vielleicht hilft es Ihnen, sich etwas besseres auszudenken, wenn es für Ihre Zwecke nicht ausreicht.

9

Hier ist ein wenig mehr Pandas-onic Art und Weise, es zu tun:

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

Beachten Sie, dass eine dieser erfordert, dass Sie pandas zumindest bei 9da899b oder neuer verwenden. Wenn Sie nicht dann sind, können Sie die booldtype auf ein Guss int64 oder 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: kann nicht float NaN umwandeln integer' 'ts.notnull.cumsum()' auf Pandas 0.12. Ich bin nicht sicher, warum dies für eine boolesche Reihe auftreten würde. – machow

+0

Das sollte durch ['9da899b'] behoben worden sein (https://github.com/pydata/pandas/commit/9da899ba3d1099d7456adb32ea129547f152dee8) –

+0

@Closed Stellen Sie sicher, dass Sie sind auf dem neuesten Stand und lassen Sie mich wissen, wenn es immer noch nicht funktioniert. –

2

Wenn Sie eine ähnliche boolean Series b annehmen können, versuchen

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

aus Ihrer Serie starten ts, entweder b = (ts == 1) oder b = ~ts.isnull().

4

Noch mehr Pandas-onic Art und Weise, es zu tun:

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

Im Gegensatz zu dem MATLAB-Code, das funktioniert auch für Werte von 1 verschieden