Python 使用groupby获取组中具有最大值的行
在按Python 使用groupby获取组中具有最大值的行,python,pandas,max,pandas-groupby,Python,Pandas,Max,Pandas Groupby,在按['Sp','Mt']列分组后,如何查找熊猫数据帧中具有计数列最大值的所有行 示例1:以下数据帧,我通过['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 MM
['Sp','Mt']
列分组后,如何查找熊猫数据帧中具有计数
列最大值的所有行
示例1:以下数据帧,我通过['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**
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
预期输出:获取组间计数最大的结果行,如:
0 MM1 S1 a **3**
2 MM1 S3 cb **5**
3 MM2 S3 mk **8**
4 MM2 S4 bg **10**
8 MM4 S2 uyi **7**
示例2:我根据['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**
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
对于上面的示例,我希望得到all每个组中count
等于max的行,例如:
MM2 S4 bg 10
MM4 S2 cb 8
MM4 S2 uyi 8
要获取原始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
请注意,如果每个组有多个max值,则将返回所有值
更新
有可能这就是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
在一个相对较大的数据帧(约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']]
对我来说,最简单的解决方案是当count等于最大值时保持值。因此,以下一行命令就足够了:
df[df['count'] == df.groupby(['Mt'])['count'].transform(max)]
您可以按计数对数据帧进行排序,然后删除重复项。我认为这更容易:
df.sort_values('count', ascending=False).drop_duplicates(['Sp','Mt'])
简单的解决方案是应用: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])
使用
groupby
和idxmax
方法:
日期
传输到日期时间
:
df['date']=pd.to_datetime(df['date'])
日期
的max
索引,在组之后按ad\u id
:
idx=df.groupby(by='ad_id')['date'].idxmax()
df_max=df.loc[idx,]
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
您可能不需要使用分组方式,使用
排序\u值
+删除重复项
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
我在许多集团运营中都使用了这种功能性风格:
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\u index(drop=True)
通过删除组索引将您恢复到原始索引。意识到将“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
尝试在groupby对象上使用“nlargest”。使用nlargest的优点是,它返回从中获取“nlargest项”的行的索引。
注意:我们对索引的第二(1)个元素进行切片,因为本例中的索引由元组组成(例如(s1,0))
总的来说,有很多方法,但哪一种更快
import pandas as pd
import numpy as np
import time
df = pd.DataFrame(np.random.randint(1,10,size=(1000000, 2)), columns=list('AB'))
start_time = time.time()
df1idx = df.groupby(['A'])['B'].transform(max) == df['B']
df1 = df[df1idx]
print("---1 ) %s seconds ---" % (time.time() - start_time))
start_time = time.time()
df2 = df.sort_values('B').groupby(['A']).tail(1)
print("---2 ) %s seconds ---" % (time.time() - start_time))
start_time = time.time()
df3 = df.sort_values('B').drop_duplicates(['A'],keep='last')
print("---3 ) %s seconds ---" % (time.time() - start_time))
start_time = time.time()
df3b = df.sort_values('B', ascending=False).drop_duplicates(['A'])
print("---3b) %s seconds ---" % (time.time() - start_time))
start_time = time.time()
df4 = df[df['B'] == df.groupby(['A'])['B'].transform(max)]
print("---4 ) %s seconds ---" % (time.time() - start_time))
start_time = time.time()
d = df.groupby('A')['B'].nlargest(1)
df5 = df.iloc[[i[1] for i in d.index], :]
print("---5 ) %s seconds ---" % (time.time() - start_time))
获胜者是
- --1)0.03337574005126953秒---
- --2)0.1346898078918457秒---
- --3)0.1024355883666992秒---
- --3b)0.1004343032836914秒---
- --4)0.028397560119628906秒---
- --5)0.07552886009216309秒---
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.sort_values("count", ascending=False).groupby(["sp", "mt"]).first().reset_index()
你的数据框是什么格式的?我不明白。什么是团体?为什么结果中的第二行以
13
开头?这个答案是我能找到的最快的解决方案:类似于这个问题,任何人都可以回答这个问题:谢谢。事实上,这个答案要快得多。对于大型数据集,转换似乎很慢。你能添加注释来解释每一行的作用吗?fwiw:我发现@Zelazny7中更优雅的解决方案对我的~100K行执行了很长时间,但这一行运行得相当快。(我现在运行的是过时的0.13.0,这可能会导致速度变慢)。但是这样做df[df['count']==df['count\u max']]
将丢失NaN行,以及上面的答案。我强烈建议使用这种方法,对于更大的数据帧,使用.appy()或.agg()要快得多。非常好!快速处理较大的帧(25k行)对于那些对Python有点陌生的人,您需要将其分配给一个新变量,它不会更改当前的df变量。@Samir或使用inplace=True
作为drop\u duplicates
的参数,当只需要其中一行具有相同的最大值时,这是一个很好的答案,但是,如果我需要具有最大值的所有行,它将无法按预期工作。我的意思是,如果数据帧是pd.dataframe({'sp':[1,1,2],'mt':[1,1,2],'value':[2,2,3]},则在sp==1和mt==2的组中,将有两行具有相同的最大值2@Rani@Zelazny7,有没有一种方法可以采用这个答案来应用于按一列分组,然后查看两列并对其进行最大化,以获得两列中较大的一列?我无法实现这一点。我目前拥有的是:def greater(Merge,maximumA,maximumB):a=Merge[maximumA]b=Merge[maximumB]return max(a,b)Merge.groupby(“搜索词”).apply(更大,“Ratio_x”,“Ratio_y”)@Zelazny7我使用的是第二种,idx
方法。但是,我只能为每个组提供一个最大值(我的数据有几个重复的max)。有没有办法用你的解决方案来解决这个问题?事实上,这对我不起作用。我无法跟踪问题,因为dataframe如果退出大,但@Rani的解决方案有效。Hi Zearzny,如果我想取前3个最大行而不是一个最大值,我如何调整你的代码?transform
方法在数据集足够大,首先获取最大值,然后合并数据帧会更好。提问者在这里指定了“我想获取每组中计数等于max的所有行”
,而idxmax
根据文档(0.21)返回最大超出请求轴第一次出现的索引”这是一个很好的解决方案,但对于一个不同的问题,这不仅比t快一个数量级
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.sort_values("count", ascending=False).groupby(["sp", "mt"]).first().reset_index()