pandas grouptarafından gruplar içinde sırala


167

Veri çerçevemi iki sütuna göre gruplandırmak ve ardından gruplar içindeki toplu sonuçları sıralamak istiyorum.

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

Şimdi sayım sütununu grupların her birinde azalan sırada sıralamak istiyorum. Ve sonra sadece ilk üç satırı alın. Gibi bir şey almak için:

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

Yanıtlar:


147

Yapmak istediğiniz şey aslında yine bir groupby'dir (ilk groupby'nin sonucu olarak): grup başına ilk üç unsuru sıralayın ve alın.

İlk grubun sonucundan başlayarak:

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

Endeksin ilk seviyesine göre gruplandırıyoruz:

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

Sonra her grubu sıralamak ('sipariş etmek') ve ilk üç unsuru almak istiyoruz:

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

Ancak, bunun için bunu yapmak için bir kısayol işlevi vardır 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

Grup başına ilk üç sonuçta yer almayan her şeyi özetlemenin ve bunları her iş için "diğer" adlı bir kaynak grubuna eklemenin bir yolu var mı?
JoeDanger

32
orderkullanımı kullanımdan kaldırıldı sort_valuesyerine
zthomas.nc

Harika cevap için teşekkürler. Bir sonraki adım için, sıralama düzenini groupby sütunundaki değerlere göre atamanın bir yolu var mı? Örneğin, değer 'Satın Al' ise artan ve değer 'Sat' ise azalan şekilde sıralayın.
Bowen Liu

174

İlk önce sıralamayı yaparak ve her grubun ilk 3'ünü almak için kafa kullanarak tek seferde de yapabilirsiniz.

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
groupbySiparişin korunduğunu garanti ediyor mu ?
toto_tico

52
Öyle görünüyor; dan GroupBy belgelenmesi : GroupBy her grup içinde satır düzenini korur
toto_tico

10
toto_tico- Bu doğrudur, ancak bu ifadenin yorumlanmasında özen gösterilmelidir. TEK GRUP İÇİNDE satırların sırası korunur, ancak groupby varsayılan olarak bir sort = True deyimine sahiptir, bu da grupların kendilerinin anahtar üzerinde sıralanmış olabileceği anlamına gelir. Başka bir deyişle, veri çerçevemde anahtarlar varsa (girişte) 3 2 2 1, .. nesneye göre gruplama 3 grubu 1 2 3 (sıralı) sırayla gösterir. Grup sırasının ve satır sırasının korunduğundan emin olmak için sort = False kullanın.
user2103050

4
head (3) 3'ten fazla sonuç veriyor?
Nabin

27

Sıralı sıralamada ilk 3 almanın ve gruplar arasında sıralama yapmanın diğer bir örneği:

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

Bunu Yerine Deneyin

'groupby' yapmanın ve azalan sırada sıralama yapmanın basit yolu

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

8

Bir sütunu toplamanız gerekmiyorsa, @ tvashtar'ın yanıtını kullanın. Toplamanız gerekiyorsa, @joris'in cevabını veya buna çok benzeyen cevabı kullanabilirsiniz.

df.groupby(['job']).apply(lambda x: (x.groupby('source')
                                      .sum()
                                      .sort_values('count', ascending=False))
                                     .head(3))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.