groupby를 사용하여 그룹에서 최대 개수를 가진 행을 가져옵니다.


244

열로 count그룹화 한 후 팬더 데이터 프레임에서 열의 최대 값을 갖는 모든 행을 어떻게 찾 ['Sp','Mt']습니까?

예제 1 : 다음 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**

예상 출력 : 그룹 간 개수가 최대 인 결과 행을 가져옵니다.

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

예제 2 : 이 데이터 프레임은 다음과 같이 그룹화됩니다 ['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

위의 예에서, 각 그룹에서 max와 같은 모든 행 을 가져 count오려고합니다.

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

데이터 프레임의 형식은 무엇입니까?
David Robinson

2
나는 그것을 얻지 못한다. 정확히 그룹은 무엇입니까? 결과의 두 번째 줄은 왜 시작 1 3합니까?
Jo So


1
이 답변은 내가 찾을 수있는 가장 빠른 솔루션입니다 : stackoverflow.com/a/21007047/778533
tommy.carstensen

이 질문과 유사하게 누구나 다음에 대답 할 수 있습니까? stackoverflow.com/questions/62069465/… 감사합니다.
ds_Abc

답변:


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

원본 DF의 색인을 얻으려면 다음을 수행하십시오.

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

그룹당 최대 값이 여러 개인 경우 모두 반환됩니다.

최신 정보

우박 메리 기회에 이것이 OP가 요청하는 것입니다.

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,이 답변을 채택하여 열별로 그룹화 한 다음 2 열을보고 최대 두 개를 사용하여 두 개 중 더 큰 것을 얻는 방법이 있습니까? 나는 그것을 작동시킬 수 없다. 내가 현재 가지고있는 것 : def Greater (Merge, maximumA, maximumB) : a = Merge [maximumA] b = Merge [maximumB] return max (a, b) Merger.groupby ( "Search_Term"). apply (Greater, "Ratio_x ","Ratio_y ")
mathlover

3
@ Zelazny7 나는 두 번째 idx접근법을 사용하고 있습니다. 그러나 각 그룹에 대해 최대 한도까지만 감당할 수 있습니다 (그리고 내 데이터에는 몇 개의 중복 최대 값이 있습니다). 솔루션 으로이 문제를 해결할 수있는 방법이 있습니까?
3pitt

실제로, 그것은 나를 위해 작동하지 않습니다. dataframe 경우 큰 종료 때문에 문제를 추적 할 수는 없지만, @Rani에 의한 해결책은 잘 작동
Ladenkov 블라디슬라프

안녕 Zealzny, 하나의 최대 값 대신에 최대 3 개의 최대 행을 가져 오려면 어떻게 코드를 조정할 수 있습니까?
Zephyr

transform데이터 세트가 충분히 클 때 메소드는 풀 성능을 가질 수 있습니다. 먼저 최대 값을 얻은 다음 데이터 프레임을 병합하는 것이 좋습니다.
우즈 첸

170

dataFrame을 개수별로 정렬 한 다음 중복을 제거 할 수 있습니다. 더 쉽다고 생각합니다.

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

4
아주 좋아요! 느린 프레임으로 빠르게 (25k 행)
놀란 Conaway

2
파이썬을 처음 접하는 사람들에게는 이것을 새로운 변수에 할당해야합니다. 현재 df 변수는 변경하지 않습니다.
Tyler

1
@Samir 또는 사용 inplace = True에 대한 인수로drop_duplicates
TMrtSmith

5
이것은 최대 값이 동일한 행 중 하나만 필요할 때 큰 대답이지만 최대 값을 가진 모든 행이 필요한 경우 예상대로 작동하지 않습니다.
우즈 첸

1
@WoodsChen, [sp, mt]의 복제본을 삭제하므로 예제에서 출력은 한 행만되어야합니다.
Rani

54

쉬운 해결책은 idxmax () 함수 를 적용 하여 최대 값을 가진 행의 인덱스를 얻는 것입니다. 이것은 그룹에서 최대 값을 가진 모든 행을 필터링합니다.

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
질문자 여기서 규정 "I want to get ALL the rows where count equals max in each group"하면서, idxmax Return[s] index of first occurrence of maximum over requested axis"워드 프로세서 (0.21)에 따라.
최대 전력

1
이것은 좋은 해결책이지만, 다른 문제
카를로스 수자

33

비교적 큰 DataFrame (~ 400k 행)에서 Zelazny가 제안한 솔루션을 시도한 결과 매우 느립니다. 다음은 내 데이터 세트에서 수십 배 더 빠르게 실행되는 대안입니다.

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
실제로 이것은 훨씬 빠릅니다. 큰 데이터 세트의 경우 변환 속도가 느린 것 같습니다.
goh

1
각 줄의 기능을 설명하는 주석을 추가 할 수 있습니까?
tommy.carstensen

fwiw : @ Zelazny7의보다 우아하게 보이는 솔루션이 ~ 100K 행 세트에서 실행하는 데 오랜 시간이 걸렸지만이 솔루션은 매우 빠르게 실행되었습니다. (현재 속도가 느린 0.13.0을 실행 중이며 속도가 느려질 수 있습니다).
Roland

2
그러나 이렇게하면 df[df['count'] == df['count_max']]위의 답변뿐만 아니라 NaN 행이 손실됩니다.
Qy Zuo

이 방법을 사용하는 것이 좋습니다. 더 큰 데이터 프레임의 경우 .appy () 또는 .agg ()를 사용하는 것이 훨씬 빠릅니다.
Touya D. Serdan

18

sort_values+를 사용하여 by by group과 관련이 없을 수도 있습니다.drop_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

또한 거의 동일한 논리를 사용하여 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

이것은 다른 솔루션보다 적어도 10 배 빠를뿐만 아니라 원래 데이터 프레임을 구성하는 과정에서 단순히 체인으로 연결하는 이점이 있습니다.
클레이

항상 Mr Wen 씨의 훌륭한 답변에 감사드립니다.
Datanovice

7

나에게 가장 쉬운 해결책은 count가 최대 일 때 가치를 유지하는 것입니다. 따라서 다음과 같은 한 줄 명령으로 충분합니다.

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

4

사용 groupbyidxmax방법 :

  1. datedatetime다음으로 전송 :

    df['date']=pd.to_datetime(df['date'])
  2. 의 인덱스 얻을 maxdate, 후를 groupyby ad_id:

    idx=df.groupby(by='ad_id')['date'].idxmax()
  3. 원하는 데이터를 얻습니다.

    df_max=df.loc[idx,]

밖으로 [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

실현 ""nlargest "적용" 하는 객체를 GROUPBY 잘으로 작동합니다 :

추가 장점- 필요한 경우 상위 n 개 값을 가져올 수도 있습니다 .

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 객체에서 "nlargest"를 사용해보십시오. nlargest를 사용하면 "가장 큰 항목"을 가져온 행의 인덱스가 반환된다는 이점이 있습니다. 참고 :이 경우 인덱스는 튜플 (예 : (s1, 0))로 구성되므로 인덱스의 second (1) 요소를 슬라이스합니다.

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

여기에 이미지 설명을 입력하십시오


1

많은 그룹 작업에이 기능 스타일을 사용하고 있습니다.

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) 그룹 색인을 삭제하여 원래 색인으로 돌아갑니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.