2

I want to group my dataframe by two columns and then sort the aggregated results within the groups.

In [167]:df

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
df.groupby(['job','source']).agg({'count':sum})
Out[168]:

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

I would now like to sort the count column in descending order within each of the groups. And then take only the top three rows. To get something like:

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

I want to further sort this problem w.r.t job, so if the sum of count for sales is more, I want the data to be printed as

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

I am unable to get the top 5 job

Sajan
  • 1,247
  • 1
  • 5
  • 13

2 Answers2

2

IIUC, we can do a further groupby and use nlargest(3) to get the top n values.

then we can create an ordered list to sort your top values to sort and create a categorical column.

s = df.groupby(['job','source']).agg({'count':sum}).groupby(level=0)['count']\
.nlargest(3).reset_index(0,drop=True).to_frame()


# see which of your indices is higher and create a sorting list.

sorter = s.groupby(level=0)['count'].sum().sort_values(ascending=False).index
#Index(['sales', 'market'], dtype='object', name='job')

s['sort'] = pd.Categorical(s.index.get_level_values(0),sorter)


df2 = s.sort_values('sort').drop('sort',axis=1)

print(df2)

               count
job    source       
sales  E           7
       C           6
       B           4
market A           5
       D           4
       B           3
Umar.H
  • 22,559
  • 7
  • 39
  • 74
1

You could use the sort_values mentioned in another similar answer sorting after aggregation and again group by job to get the top N from the job like,

>>> df
   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
>>> agg = df.groupby(['job','source']).agg({'count':sum})
>>> agg
               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
>>> agg.reset_index().sort_values(['job', 'count'], ascending=False).set_index(['job', 'source']).groupby('job').head(3)
               count
job    source       
sales  E           7
       C           6
       B           4
market A           5
       D           4
       B           3
>>> 
han solo
  • 6,390
  • 1
  • 15
  • 19