2013-08-12 38 views
9

Nếu tôi có một pandas.core.series.Series tên ts của hoặc là 1 hoặc NaN của như thế này:Cumsum reset tại 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 

Tôi muốn tính toán cumsum của serie này, nhưng nó phải được thiết lập lại (thiết lập để zero) tại vị trí của các NaN như sau:

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 

Lý tưởng nhất là tôi muốn có giải pháp vector!

tôi đã từng nhìn thấy một câu hỏi tương tự với Matlab: Matlab cumsum reset at NaN?

nhưng tôi không biết làm thế nào để dịch dòng này d = diff([0 c(n)]);

Trả lời

7

Một NumPy dịch mã đơn giản Matlab của bạn là thế này:

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) 

Thực thi mã này trả về kết quả array([ 1., 2., 3., 0., 1., 2., 3., 4., 0., 1.]). Giải pháp này sẽ chỉ có giá trị như bản gốc, nhưng có lẽ nó sẽ giúp bạn đưa ra một cái gì đó tốt hơn nếu nó không đủ cho các mục đích của bạn.

9

Đây là một cách gấu trúc-onic nhẹ hơn để làm điều đó:

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

Lưu ý rằng một trong những đòi hỏi mà bạn đang sử dụng pandas ít nhất là ở 9da899b hoặc mới hơn. Nếu bạn không phải là sau đó bạn có thể cast booldtype một int64 hoặc 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: không thể chuyển đổi phao NaN để integer' cho 'ts.notnull.cumsum()' trên gấu trúc 0,12. Tôi không chắc tại sao điều này lại xảy ra với một chuỗi boolean .. – machow

+0

Điều đó phải được sửa bởi ['9da899b'] (https://github.com/pydata/pandas/commit/9da899ba3d1099d7456adb32ea129547f152dee8) –

+0

@Closed Đảm bảo bạn đã cập nhật và cho tôi biết nếu nó vẫn không hoạt động. –

2

Nếu bạn có thể chấp nhận một boolean Dòng tương tự b, hãy thử

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

Bắt đầu từ Series ts, hoặc b = (ts == 1) hoặc b = ~ts.isnull().

4

Thậm chí nhiều hơn gấu trúc-onic cách để làm điều đó:

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

Trái với mã MATLAB, điều này cũng làm việc cho các giá trị khác nhau từ 1.