groupbyを使用してグループの最大数を持つ行を取得します。


243

列で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
わかりません。グループとは正確には何ですか?結果の2行目がなぜ始まるの1 3ですか?
Jo So

stackoverflow.com/questions/18879782/… 役に立つかもしれません
J_Arthur 2013

1
この答えは、私が見つけることができる最速のソリューションです:stackoverflow.com/a/21007047/778533
tommy.carstensen

この質問と同様に、誰でもこれに答えてください:stackoverflow.com/questions/62069465/… ありがとう。
ds_Abc

回答:


323
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つの列を調べ、それらの最大値を取得して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 2017年

3
@ Zelazny7 2番目のidxアプローチを使用しています。しかし、私は各グループの単一の最大値しか余裕がありません(そして私のデータにはいくつかの重複最大値があります)。あなたの解決策でこれを回避する方法はありますか?
ビョークは1

実際、それは私にはうまくいきません。私は問題を追跡できません。データフレームが大きく終了した場合ですが、@ Raniによる解決策はうまく機能します
Ladenkov Vladislav

こんにちはZealzny。1つの最大値ではなく、上位3つの最大行を取得する場合、コードを調整するにはどうすればよいですか?
Zephyr

transformデータセットが十分に大きい場合、メソッドはプールのパフォーマンスを発揮する可能性があります。最初に最大値を取得してから、データフレームをマージする方が適しています。
ウッズチェン

169

カウントでdataFrameをソートしてから、重複を削除できます。私はそれが簡単だと思います:

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

4
非常に素晴らしい!ゆったりとしたフレーム(25k行)で高速
Nolan Conaway

2
Pythonをある程度使用している人は、これを新しい変数に割り当てる必要があります。現在のdf変数は変更されません。
タイラー

1
@Samirまたはinplace = True引数として使用drop_duplicates
TMrtSmith

5
これは、同じ最大値を持つ行が1つだけ必要な場合の優れた回答ですが、最大値を持つすべての行が必要な場合、期待どおりに機能しません。
Woods Chen、

1
@WoodsChen、[sp、mt]の重複を削除するため、この例では、出力は1行のみになります。
ラニ

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)に従います。
Max Power

1
これは素晴らしい解決策ですが、別の問題
Carlos Souza

33

比較的大きなDataFrame(約40万行)で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
実際、これははるかに高速です。大きなデータセットでは変換が遅いようです。
go

1
各行の機能を説明するコメントを追加できますか?
tommy.carstensen 2017年

fwiw:@ Zelazny7からのよりエレガントな外観のソリューションは、10万行以上のセットの実行に長い時間がかかることを発見しましたが、これはかなり高速に実行されました。(私は今や時代遅れの0.13.0を実行していますが、これは遅延の原因となる可能性があります)。
ローランド

2
しかし、これをdf[df['count'] == df['count_max']]行うと、NaN行と上記の回答が失われます。
Qy Zuo

このアプローチを使用することを強くお勧めします。大きなデータフレームの場合、.appy()または.agg()を使用する方がはるかに高速です。
Touya D. Serdan 2018

18

sort_values+ を使用してgroup byを行う必要がない場合があります。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

これは、他のソリューションよりも桁違いに速いだけでなく(少なくとも私の使用例では)、元のデータフレームの構築の一部として単純にチェーンするという追加の利点があります。
クレイ

ウェンさんと同じように素晴らしい答えをありがとう、これは簡単だと思って頭を掻きました。
Datanovice

7

私にとって、最も簡単な解決策は、countがmaximumに等しいときに値を保持することです。したがって、次の1行のコマンドで十分です。

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

4

使用groupbyidxmax方法:

  1. col dateに転送datetime

    df['date']=pd.to_datetime(df['date'])
  2. maxの列のインデックスを取得します。dategroupyby ad_id

    idx=df.groupby(by='ad_id')['date'].idxmax()
  3. 必要なデータを取得します。

    df_max=df.loc[idx,]

Out [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を使用する利点は、「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) group-indexを削除すると、元のインデックスに戻ります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.