2015-01-08 49 views
57

データフレームを2つの列でグループ化し、グループ内で集計結果を並べ替える必要があります。pandas groupbyグループ内で並べ替え

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 

ここで、カウントの列を各グループ内で降順にソートしたいと考えています。そして、上位3行だけを取る。以下のようなものを取得するには:

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

答えて

52

を何がやりたいことは実際には、再び(最初GROUPBYの結果に)GROUPBYです:ソート、グループごとに最初の3つの要素を取ります。最初GROUPBYの結果から始め

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

我々は、インデックスの最初のレベルによってグループ:

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

はその後、我々は(「順序」)をソートしたい各グループと最初の3つの要素を取る:

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

グループごとに上位3つの結果に含まれていないものすべてを合計し、ジョブごとに「その他」というソースグループに追加する方法はありますか? – 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を取って、グループ内のソートの他の例です:あなたはtvashtarの答え@使用し、その後、列を合計する必要がない場合

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

。もしあなたが合計する必要があるなら、あなたは@ jorisの答えを使うことができます。これは非常に似ています。

df.groupby(['job']).apply(lambda x: (x.groupby('source') 
             .sum() 
             .sort_values('count', ascending=False)) 
            .head(3)) 
関連する問題