Groupby kullanarak gruplarda maksimum sayıya sahip Satır (lar) ı alın


244

Sütunlara countgöre gruplandırdıktan sonra, panda veri çerçevesindeki maksimum sütun değerine sahip tüm satırları nasıl bulurum ['Sp','Mt']?

Örnek 1: göre grupladığım aşağıdaki dataFrame ['Sp','Mt']:

   Sp   Mt Value   count
0  MM1  S1   a      **3**
1  MM1  S1   n      2
2  MM1  S3   cb     5
3  MM2  S3   mk      **8**
4  MM2  S4   bg     **10**
5  MM2  S4   dgd      1
6  MM4  S2  rd     2
7  MM4  S2   cb      2
8  MM4  S2   uyi      **7**

Beklenen çıktı: sayısı gruplar arasında maksimum olan sonuç satırlarını alın, örneğin:

0  MM1  S1   a      **3**
1 3  MM2  S3   mk      **8**
4  MM2  S4   bg     **10** 
8  MM4  S2   uyi      **7**

Örnek 2: göre grupladığım bu veri çerçevesi ['Sp','Mt']:

   Sp   Mt   Value  count
4  MM2  S4   bg     10
5  MM2  S4   dgd    1
6  MM4  S2   rd     2
7  MM4  S2   cb     8
8  MM4  S2   uyi    8

Yukarıdaki örnek için, her grupta max eşittir tüm satırları almak istiyorum count, örneğin:

MM2  S4   bg     10
MM4  S2   cb     8
MM4  S2   uyi    8

Veri çerçeveniz hangi formatta?
David Robinson

2
Anlamıyorum. Grup tam olarak nedir? Sonuçtaki ikinci satır neden başlar 1 3?
Jo So


1
Bu cevap bulabildiğim en hızlı çözüm: stackoverflow.com/a/21007047/778533
tommy.carstensen

Bu soruya benzer şekilde, lütfen herkes buna cevap verebilir mi: stackoverflow.com/questions/62069465/… Teşekkürler.
ds_Abc

Yanıtlar:


325
In [1]: df
Out[1]:
    Sp  Mt Value  count
0  MM1  S1     a      3
1  MM1  S1     n      2
2  MM1  S3    cb      5
3  MM2  S3    mk      8
4  MM2  S4    bg     10
5  MM2  S4   dgd      1
6  MM4  S2    rd      2
7  MM4  S2    cb      2
8  MM4  S2   uyi      7

In [2]: df.groupby(['Mt'], sort=False)['count'].max()
Out[2]:
Mt
S1     3
S3     8
S4    10
S2     7
Name: count

Orijinal DF'nin indekslerini almak için şunları yapabilirsiniz:

In [3]: idx = df.groupby(['Mt'])['count'].transform(max) == df['count']

In [4]: df[idx]
Out[4]:
    Sp  Mt Value  count
0  MM1  S1     a      3
3  MM2  S3    mk      8
4  MM2  S4    bg     10
8  MM4  S2   uyi      7

Grup başına birden fazla maksimum değeriniz varsa, bunların hepsinin döndürüleceğini unutmayın.

Güncelleme

Dolu bir şansta OP'nin talep ettiği şey budur:

In [5]: df['count_max'] = df.groupby(['Mt'])['count'].transform(max)

In [6]: df
Out[6]:
    Sp  Mt Value  count  count_max
0  MM1  S1     a      3          3
1  MM1  S1     n      2          3
2  MM1  S3    cb      5          8
3  MM2  S3    mk      8          8
4  MM2  S4    bg     10         10
5  MM2  S4   dgd      1         10
6  MM4  S2    rd      2          7
7  MM4  S2    cb      2          7
8  MM4  S2   uyi      7          7

@ Zelazny7, bir sütuna göre gruplama ve sonra 2 sütuna bakmak ve ikisinden daha büyük almak için en fazla bunları yapmak için bu cevabı benimsemenin bir yolu var mı? Bunu iţletemiyorum. Şu anda sahip olduğum şey: def Greater (Birleştir, maximumA, maximumB): a = Birleştir [maximumA] b = [maksimumB] Birleştir maksimum (a, b) Merger.groupby ("Search_Term"). Uygula (Büyük, "Ratio_x "," Ratio_y ")
mathlover

3
@ Zelazny7 İkinci idxyaklaşımı kullanıyorum. Ancak, her grup için yalnızca tek bir maksimuma yetebilirim (ve verilerimin birkaç yinelenen maksimum değeri var). çözümünüzle bunu çözmenin bir yolu var mı?
3pitt

aslında, bu benim için işe yaramıyor. Sorunu takip edemem, çünkü veri çerçevesi büyük çıkarsa, ancak @Rani'nin çözümü iyi çalışıyor
Ladenkov Vladislav

Merhaba Zealzny, Bir maksimum değer yerine ilk 3 maksimum satırı almak istersem, Kodunuzu nasıl değiştirebilirim?
Zephyr

transformveri kümesi yeterince büyük olduğunda yöntem havuz performansına sahip olabilir, önce maksimum değeri alın, sonra veri çerçevelerini birleştirin daha iyi olacaktır.
Woods Chen

170

DataFrame öğesini sayıya göre sıralayabilir ve daha sonra kopyaları kaldırabilirsiniz. Bence daha kolay:

df.sort_values('count', ascending=False).drop_duplicates(['Sp','Mt'])

4
Çok hoş! Büyük çerçevelerle hızlı (25 bin satır)
Nolan Conaway

2
Python ile biraz yeni olanlar için, bunu yeni bir değişkene atamanız gerekir, geçerli df değişkenini değiştirmez.
Tyler

1
@Samir ya da inplace = Trueargüman olarak kullandrop_duplicates
TMrtSmith

5
Aynı maksimum değerlere sahip satırlardan yalnızca birine ihtiyaç duyduğunuzda bu harika bir cevaptır, ancak maksimum değerlere sahip tüm satırlara ihtiyaç duyduğumda beklendiği gibi çalışmaz.
Woods Chen

1
@WoodsChen, [sp, mt] kopyalarını bırakır, bu nedenle örneğin örnekte çıktı yalnızca bir satır olmalıdır.
Rani

54

Uygulanması kolay bir çözüm olabilir: idxmax () işlevi, maksimum değerlere sahip satır indeksleri elde etmek için. Bu, gruptaki maksimum değere sahip tüm satırları filtreleyecektir.

In [365]: import pandas as pd

In [366]: df = pd.DataFrame({
'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
'count' : [3,2,5,8,10,1,2,2,7]
})

In [367]: df                                                                                                       
Out[367]: 
   count  mt   sp  val
0      3  S1  MM1    a
1      2  S1  MM1    n
2      5  S3  MM1   cb
3      8  S3  MM2   mk
4     10  S4  MM2   bg
5      1  S4  MM2  dgb
6      2  S2  MM4   rd
7      2  S2  MM4   cb
8      7  S2  MM4  uyi


### Apply idxmax() and use .loc() on dataframe to filter the rows with max values:
In [368]: df.loc[df.groupby(["sp", "mt"])["count"].idxmax()]                                                       
Out[368]: 
   count  mt   sp  val
0      3  S1  MM1    a
2      5  S3  MM1   cb
3      8  S3  MM2   mk
4     10  S4  MM2   bg
8      7  S2  MM4  uyi

### Just to show what values are returned by .idxmax() above:
In [369]: df.groupby(["sp", "mt"])["count"].idxmax().values                                                        
Out[369]: array([0, 2, 3, 4, 8])

4
Sorgulayıcı Burada belirtilen "I want to get ALL the rows where count equals max in each group"süre, idxmax Return[s] index of first occurrence of maximum over requested axis"docs (0.21) 'e göre.
Maksimum Güç

1
Bu harika bir çözüm, ancak farklı bir sorun için
Carlos Souza

33

Zelazny tarafından nispeten büyük bir DataFrame (~ 400k satır) üzerinde önerilen çözümü denedikten sonra çok yavaş buldum. İşte veri kümemde büyüklük sıralarını daha hızlı çalıştırdığımı bulduğum bir alternatif.

df = pd.DataFrame({
    'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4', 'MM4'],
    'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
    'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
    'count' : [3,2,5,8,10,1,2,2,7]
    })

df_grouped = df.groupby(['sp', 'mt']).agg({'count':'max'})

df_grouped = df_grouped.reset_index()

df_grouped = df_grouped.rename(columns={'count':'count_max'})

df = pd.merge(df, df_grouped, how='left', on=['sp', 'mt'])

df = df[df['count'] == df['count_max']]

1
aslında bu çok daha hızlı. büyük veri kümesi için dönüşüm yavaş görünüyor.
goh

1
Her satırın ne yaptığını açıklamak için yorumlar ekleyebilir misiniz?
tommy.carstensen

fwiw: @ Zelazny7'den daha şık görünümlü bir çözüm buldum ~ 100K sıralarımın yürütülmesi uzun zaman aldı, ama bu oldukça hızlı bir şekilde çalıştı. (Yavaşlığı hesaba katabilecek, artık kullanılmayan 0.13.0 kullanıyorum).
Roland

2
Ancak bunu yapmak df[df['count'] == df['count_max']]NaN satırlarını ve yukarıdaki cevapları kaybedecektir.
Qy Zuo

Bu yaklaşımı kullanmanızı şiddetle tavsiye ederim, daha büyük veri çerçeveleri için .appy () veya .agg () kullanımı çok daha hızlıdır.
Touya D. Serdan

18

sort_values+ Kullanarak grupla yapmanız gerekmeyebilirdrop_duplicates

df.sort_values('count').drop_duplicates(['Sp','Mt'],keep='last')
Out[190]: 
    Sp  Mt Value  count
0  MM1  S1     a      3
2  MM1  S3    cb      5
8  MM4  S2   uyi      7
3  MM2  S3    mk      8
4  MM2  S4    bg     10

Ayrıca neredeyse aynı mantık kullanarak tail

df.sort_values('count').groupby(['Sp', 'Mt']).tail(1)
Out[52]: 
    Sp  Mt Value  count
0  MM1  S1     a      3
2  MM1  S3    cb      5
8  MM4  S2   uyi      7
3  MM2  S3    mk      8
4  MM2  S4    bg     10

Bu sadece diğer çözümlerden daha hızlı bir büyüklük sırası değil (en azından benim kullanım durumum için), aynı zamanda orijinal veri çerçevesinin yapısının bir parçası olarak basitçe zincirleme avantajına sahiptir.
Clay

Kesinlikle bunun basit olduğunu düşünerek başımı kaşıyordum, her zamanki gibi parlak cevabınız için teşekkürler Bay Wen.
Datanovice

7

Benim için en kolay çözüm, sayı maksimuma eşit olduğunda değeri korumak olacaktır. Bu nedenle, aşağıdaki bir satır komutu yeterlidir:

df[df['count'] == df.groupby(['Mt'])['count'].transform(max)]

4

Kullanımı groupbyve idxmaxyöntemleri:

  1. col aktarmak dateiçin datetime:

    df['date']=pd.to_datetime(df['date'])
  2. maxsütununun dizinini al date, sonra groupyby ad_id:

    idx=df.groupby(by='ad_id')['date'].idxmax()
  3. İstenen verileri alın:

    df_max=df.loc[idx,]

Çıkış [54]:

ad_id  price       date
7     22      2 2018-06-11
6     23      2 2018-06-22
2     24      2 2018-06-30
3     28      5 2018-06-22

2
df = pd.DataFrame({
'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
'count' : [3,2,5,8,10,1,2,2,7]
})

df.groupby(['sp', 'mt']).apply(lambda grp: grp.nlargest(1, 'count'))

2

Fark eden "" nlargest "uygulayarak" için nesneyi GroupBy sadece ince olarak çalışır:

Ek avantaj - gerekirse en üstteki n değerini de alabilir :

In [85]: import pandas as pd

In [86]: df = pd.DataFrame({
    ...: 'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
    ...: 'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
    ...: 'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
    ...: 'count' : [3,2,5,8,10,1,2,2,7]
    ...: })

## Apply nlargest(1) to find the max val df, and nlargest(n) gives top n values for df:
In [87]: df.groupby(["sp", "mt"]).apply(lambda x: x.nlargest(1, "count")).reset_index(drop=True)
Out[87]:
   count  mt   sp  val
0      3  S1  MM1    a
1      5  S3  MM1   cb
2      8  S3  MM2   mk
3     10  S4  MM2   bg
4      7  S2  MM4  uyi

2

Groupby nesnesinde "nlargest" komutunu kullanmayı deneyin. Nlargest kullanmanın avantajı, "en büyük öğe (ler)" in getirildiği satırların dizinini döndürmesidir. Not: Bu durumda dizinimiz tuple (örn. (S1, 0)) içerdiğinden dizinimizin ikinci (1) öğesini dilimliyoruz.

df = pd.DataFrame({
'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
'count' : [3,2,5,8,10,1,2,2,7]
})

d = df.groupby('mt')['count'].nlargest(1) # pass 1 since we want the max

df.iloc[[i[1] for i in d.index], :] # pass the index of d as list comprehension

resim açıklamasını buraya girin


1

Bu işlevsel stili birçok grup işlemi için kullanıyorum:

df = pd.DataFrame({
   'Sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4', 'MM4'],
   'Mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
   'Val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
   'Count' : [3,2,5,8,10,1,2,2,7]
})

df.groupby('Mt')\
  .apply(lambda group: group[group.Count == group.Count.max()])\
  .reset_index(drop=True)

    sp  mt  val  count
0  MM1  S1    a      3
1  MM4  S2  uyi      7
2  MM2  S3   mk      8
3  MM2  S4   bg     10

.reset_index(drop=True) grup dizinini bırakarak orijinal dizine dönmenizi sağlar.

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.