2015-01-08 174 views
57

我想按兩列對數據幀進行分組,然後對羣組內的聚合結果進行排序。熊貓羣體在羣組內排序

In [167]: 
df 

Out[167]: 
count job source 
0 2 sales A 
1 4 sales B 
2 6 sales C 
3 3 sales D 
4 7 sales E 
5 5 market A 
6 3 market B 
7 2 market C 
8 4 market D 
9 1 market E 

In [168]: 
df.groupby(['job','source']).agg({'count':sum}) 

Out[168]: 
      count 
job  source 
market A 5 
     B 3 
     C 2 
     D 4 
     E 1 
sales A 2 
     B 4 
     C 6 
     D 3 
     E 7 

我現在想按每個組中的降序對count列進行排序。然後只取前三排。要達到這樣的:

  count 
job  source 
market A 5 
     D 4 
     B 3 
sales E 7 
     C 6 
     B 4 

回答

52

你想要做的實際上又是一個GROUPBY(第一GROUPBY的結果):排序和取每組前三個元素。

從第一GROUPBY的結果開始:

In [60]: df_agg = df.groupby(['job','source']).agg({'count':sum}) 

我們組由索引的第一級:

In [63]: g = df_agg['count'].groupby(level=0, group_keys=False) 

然後我們想排序(「訂單」)各組取前三個元素:

In [64]: res = g.apply(lambda x: x.order(ascending=False).head(3)) 

但是,爲此,有一個快捷方式可以做到這一點,nlargest

In [65]: g.nlargest(3) 
Out[65]: 
job  source 
market A   5 
     D   4 
     B   3 
sales E   7 
     C   6 
     B   4 
dtype: int64 
+0

是否有一種方法可以總結每組前三項結果中未包含的所有內容,並將它們添加到每個作業的名爲「other」的源組中? – JoeDanger

+7

'order'已棄用使用'sort_values'而不是 –

40

你也可以只做到一氣呵成,首先做的那種,用頭把各組的前3。

In[34]: df.sort_values(['job','count'],ascending=False).groupby('job').head(3) 

Out[35]: 
    count  job source 
4  7 sales  E 
2  6 sales  C 
1  4 sales  B 
5  5 market  A 
8  4 market  D 
6  3 market  B 
+2

'groupby'確保訂單保存嗎? –

+8

看起來確實如此;來自[groupby的文檔](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html):__groupby保留每個組內的行的順序___ –

6

下面是對排序順序取前3名,和排序組內的其他例子:

In [43]: import pandas as pd                                      

In [44]: df = pd.DataFrame({"name":["Foo", "Foo", "Baar", "Foo", "Baar", "Foo", "Baar", "Baar"], "count_1":[5,10,12,15,20,25,30,35], "count_2" :[100,150,100,25,250,300,400,500]}) 

In [45]: df                                           
Out[45]: 
    count_1 count_2 name 
0  5  100 Foo 
1  10  150 Foo 
2  12  100 Baar 
3  15  25 Foo 
4  20  250 Baar 
5  25  300 Foo 
6  30  400 Baar 
7  35  500 Baar 


### Top 3 on sorted order: 
In [46]: df.groupby(["name"])["count_1"].nlargest(3)                                
Out[46]: 
name 
Baar 7 35 
     6 30 
     4 20 
Foo 5 25 
     3 15 
     1 10 
dtype: int64 


### Sorting within groups based on column "count_1": 
In [48]: df.groupby(["name"]).apply(lambda x: x.sort_values(["count_1"], ascending = False)).reset_index(drop=True) 
Out[48]: 
    count_1 count_2 name 
0  35  500 Baar 
1  30  400 Baar 
2  20  250 Baar 
3  12  100 Baar 
4  25  300 Foo 
5  15  25 Foo 
6  10  150 Foo 
7  5  100 Foo 
0

如果沒有需要總結一列,然後使用@ tvashtar的答案。如果你確實需要總結一下,那麼你可以使用@joris的答案或者這個與它非常相似的答案。

df.groupby(['job']).apply(lambda x: (x.groupby('source') 
             .sum() 
             .sort_values('count', ascending=False)) 
            .head(3))