2013-01-16 46 views
20

我有一個pandas.DataFrame,其中包含在連續時間點進行的測量。隨着每次測量,被觀察的系統在每個時間點都具有獨特的狀態。因此,DataFrame還包含一個包含每次測量時系統狀態的列。狀態變化比測量間隔慢得多。作爲結果,這種狀態列可能是這樣的(索引:狀態):在熊貓數據框中查找連續段

1: 3 
2: 3 
3: 3 
4: 3 
5: 4 
6: 4 
7: 4 
8: 4 
9: 1 
10: 1 
11: 1 
12: 1 
13: 1 

有一種簡單的方法來檢索連續平等國家的各段的指數。這意味着我想得到像這樣的東西:

[[1,2,3,4], [5,6,7,8], [9,10,11,12,13]] 

結果也可能是在不同於普通列表的東西。

我能想到的,到目前爲止手動遍歷行,發現段的變化點和重建從這些變化點的指數唯一的解決辦法,但我希望有一個簡單的解決方案。

回答

35

一行代碼:

df.reset_index().groupby('A')['index'].apply(np.array) 

代碼,例如:

In [1]: import numpy as np 

In [2]: from pandas import * 

In [3]: df = DataFrame([3]*4+[4]*4+[1]*4, columns=['A']) 
In [4]: df 
Out[4]: 
    A 
0 3 
1 3 
2 3 
3 3 
4 4 
5 4 
6 4 
7 4 
8 1 
9 1 
10 1 
11 1 

In [5]: df.reset_index().groupby('A')['index'].apply(np.array) 
Out[5]: 
A 
1 [8, 9, 10, 11] 
3  [0, 1, 2, 3] 
4  [4, 5, 6, 7] 

您也可以直接從GROUPBY對象訪問信息:

In [1]: grp = df.groupby('A') 

In [2]: grp.indices 
Out[2]: 
{1L: array([ 8, 9, 10, 11], dtype=int64), 
3L: array([0, 1, 2, 3], dtype=int64), 
4L: array([4, 5, 6, 7], dtype=int64)} 

In [3]: grp.indices[3] 
Out[3]: array([0, 1, 2, 3], dtype=int64) 

爲了解決這一DSM提到你可以做類似的情況:

In [1]: df['block'] = (df.A.shift(1) != df.A).astype(int).cumsum() 

In [2]: df 
Out[2]: 
    A block 
0 3  1 
1 3  1 
2 3  1 
3 3  1 
4 4  2 
5 4  2 
6 4  2 
7 4  2 
8 1  3 
9 1  3 
10 1  3 
11 1  3 
12 3  4 
13 3  4 
14 3  4 
15 3  4 

現在GROUPBY列和應用lambda函數:

In [77]: df.reset_index().groupby(['A','block'])['index'].apply(np.array) 
Out[77]: 
A block 
1 3   [8, 9, 10, 11] 
3 1   [0, 1, 2, 3] 
    4  [12, 13, 14, 15] 
4 2   [4, 5, 6, 7] 
+12

這假定值不在不連續的段中重複,例如DataFrame([3] * 4 + [4] * 4 + [1] * 4 + [3] * 4,columns = ['A '])'會將兩個3個羣組放入同一個羣組。你可以掃描那些休息時間,但這只是原始問題的另一個版本。不過,也許有一種方法可以讓熊貓'groupby'在這裏表現得更像'itertools.groupby'。 – DSM

+0

謝謝,你的第二個解決方案運作良好。實際上我有DSM描述的情況。 – languitar

+0

怎麼可能這樣做,如果你被一些偏差要組(如組包含所有值都在原來的集中+ -1相鄰值的值) – ryanjdillon

15

您可以使用np.diff()來測試段開始/結束的位置並遍歷這些結果。它是一個非常簡單的解決方案,所以可能不是最好的解決方案之一。

a = np.array([3,3,3,3,3,4,4,4,4,4,1,1,1,1,4,4,12,12,12]) 

prev = 0 
splits = np.append(np.where(np.diff(a) != 0)[0],len(a)+1)+1 

for split in splits: 
    print np.arange(1,a.size+1,1)[prev:split] 
    prev = split 

結果:

[1 2 3 4 5] 
[ 6 7 8 9 10] 
[11 12 13 14] 
[15 16] 
[17 18 19] 
+0

謝謝,實際上是由Zelazny7的解決方案是更方便,因爲我喜歡將分段存儲在DataFrame中,並自動實現這一點。 – languitar

+0

謝謝Rutger。 'np.diff()'在這裏是一個很好的建議。 – ryanjdillon