2017-04-04 40 views
3

給定一個Series,我想有效地計算出有多少觀測值發生了變化。下面是一個簡單的例子:自改變以來的高效熊貓/ numpy函數的時間

ser = pd.Series([1.2,1.2,1.2,1.2,2,2,2,4,3]) 

print(ser) 

0 1.2 
1 1.2 
2 1.2 
3 1.2 
4 2.0 
5 2.0 
6 2.0 
7 4.0 
8 3.0 

我想一個函數應用於ser這將導致:

0 0 
1 1 
2 2 
3 3 
4 0 
5 1 
6 2 
7 0 
8 0 

正如我處理大型系列我希望能有一個快速的解決方案,不涉及循環。由於

編輯如果可能的話,還想工作,爲具有相同值的一系列功能(這隻會導致加1的一系列整數)

回答

2

這裏有一個NumPy的方法 -

def array_cumcount(a): 
    idx = np.flatnonzero(a[1:] != a[:-1])+1 
    shift_arr = np.ones(a.size,dtype=int) 
    shift_arr[0] = 0 

    if len(idx)>=1: 
     shift_arr[idx[0]] = -idx[0]+1 
     shift_arr[idx[1:]] = -idx[1:] + idx[:-1] + 1 
    return shift_arr.cumsum() 

採樣運行 -

In [583]: ser = pd.Series([1.2,1.2,1.2,1.2,2,2,2,4,3,3,3,3]) 

In [584]: array_cumcount(ser.values) 
Out[584]: array([0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 2, 3]) 

運行測試 -

In [601]: ser = pd.Series(np.random.randint(0,3,(10000))) 

# @Psidom's soln 
In [602]: %timeit ser.groupby(ser).cumcount() 
1000 loops, best of 3: 729 µs per loop 

In [603]: %timeit array_cumcount(ser.values) 
10000 loops, best of 3: 85.3 µs per loop 

In [604]: ser = pd.Series(np.random.randint(0,3,(1000000))) 

# @Psidom's soln 
In [605]: %timeit ser.groupby(ser).cumcount() 
10 loops, best of 3: 30.1 ms per loop 

In [606]: %timeit array_cumcount(ser.values) 
100 loops, best of 3: 11.7 ms per loop 
+0

謝謝@Divakar。有沒有辦法調整它,以便它也適用於具有所有相同值的系列?現在,當發生這種情況時,我得到錯誤' IndexError:索引0在行'shift_arr [idx [0]] = -idx [0] + 1'處軸0的大小超出界限。 – splinter

+1

@splinter更新後處理該角落案例。 – Divakar

2

您可以使用groupby.cumcount

ser.groupby(ser).cumcount() 

#0 0 
#1 1 
#2 2 
#3 3 
#4 0 
#5 1 
#6 2 
#7 0 
#8 0 
#dtype: int64 
+0

感謝,接受@Divakar解決方案只是因爲速度。 – splinter