panda grup oleh semacam dalam kelompok


166

Saya ingin mengelompokkan dataframe saya dengan dua kolom dan kemudian mengurutkan hasil agregat dalam grup.

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

Sekarang saya ingin mengurutkan kolom hitung dalam urutan menurun di masing-masing grup. Dan kemudian hanya mengambil tiga baris teratas. Untuk mendapatkan sesuatu seperti:

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

Jawaban:


147

Apa yang ingin Anda lakukan sebenarnya adalah sebuah groupby (berdasarkan hasil dari group pertama): mengurutkan dan mengambil tiga elemen pertama per grup.

Mulai dari hasil group pertama oleh:

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

Kami mengelompokkan berdasarkan tingkat indeks pertama:

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

Lalu kami ingin mengurutkan ('memesan') masing-masing grup dan mengambil tiga elemen pertama:

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

Namun, untuk ini, ada fungsi pintas untuk melakukan ini 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

Apakah akan ada cara untuk meringkas segala sesuatu yang tidak terkandung dalam tiga hasil teratas per grup dan menambahkannya ke grup sumber yang disebut "lain" untuk setiap pekerjaan?
JoeDanger

31
ordersudah ditinggalkan penggunaan sort_valuesbukannya
zthomas.nc

Terima kasih atas jawabannya. Untuk langkah selanjutnya, apakah akan ada cara untuk menetapkan urutan penyortiran berdasarkan nilai-nilai di kolom groupby? Misalnya, mengurutkan naik jika nilainya 'Beli' dan mengurutkan turun jika nilainya adalah 'Jual'.
Bowen Liu

174

Anda juga bisa melakukannya dalam sekali jalan, dengan melakukan sortir terlebih dahulu dan menggunakan head untuk mengambil 3 pertama dari setiap grup.

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

14
Apakah groupbyjaminan bahwa pesanan tetap terjaga?
toto_tico

52
Tampaknya memang demikian; dari dokumentasi groupby : groupby mempertahankan urutan baris dalam setiap grup
toto_tico

10
toto_tico- Itu benar, namun perlu berhati-hati dalam menafsirkan pernyataan itu. Urutan baris DALAM KELOMPOK TUNGGAL dipertahankan, namun groupby memiliki semacam = Pernyataan benar secara default yang berarti kelompok itu sendiri mungkin telah diurutkan pada kunci. Dengan kata lain jika kerangka data saya memiliki kunci (pada input) 3 2 2 1, .. grup dengan objek akan menampilkan 3 grup dalam urutan 1 2 3 (diurutkan). Gunakan sort = False untuk memastikan pesanan grup dan urutan baris dipertahankan.
user2103050

4
kepala (3) memberi lebih dari 3 hasil?
Nabin

27

Berikut adalah contoh lain dari mengambil 3 teratas pada urutan diurutkan, dan mengurutkan dalam grup:

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

9

Coba ini sebagai gantinya

cara sederhana untuk melakukan 'groupby' dan menyortir dalam urutan menurun

df.groupby(['companyName'])['overallRating'].sum().sort_values(ascending=False).head(20)

8

Jika Anda tidak perlu menjumlahkan kolom, maka gunakan jawaban @ tvashtar. Jika Anda perlu menjumlahkan, maka Anda dapat menggunakan jawaban @ joris 'atau yang ini sangat mirip dengannya.

df.groupby(['job']).apply(lambda x: (x.groupby('source')
                                      .sum()
                                      .sort_values('count', ascending=False))
                                     .head(3))
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.