使用 groupby 获取组中具有最大值的行
- 2024-11-18 08:40:00
- admin 原创
- 13
问题描述:
count
按列分组后,如何找到 pandas DataFrame 中具有列最大值的所有行['Sp','Mt']
?
示例 1:以下 DataFrame:
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
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 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
预期输出:
Sp Mt Value count
4 MM2 S4 bg 10
7 MM4 S2 cb 8
8 MM4 S2 uyi 8
解决方案 1:
首先,我们可以像这样获取每个组的最大计数:
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(['Sp', 'Mt'])['count'].max()
Out[2]:
Sp Mt
MM1 S1 3
S3 5
MM2 S3 8
S4 10
MM4 S2 7
Name: count, dtype: int64
要获取原始 DF 的索引,您可以执行以下操作:
In [3]: idx = df.groupby(['Sp', 'Mt'])['count'].transform(max) == df['count']
In [4]: df[idx]
Out[4]:
Sp Mt Value count
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
请注意,如果每个组有多个最大值,则将返回所有值。
更新
万一碰上 OP 要求的正是这个:
In [5]: df['count_max'] = df.groupby(['Sp', '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 5
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
解决方案 2:
您可以按计数对 dataFrame 进行排序,然后删除重复项。我认为这更容易:
df.sort_values('count', ascending=False).drop_duplicates(['Sp','Mt'])
解决方案 3:
简单的解决方案是应用idxmax()
函数来获取具有最大值的行的索引。这将过滤掉组中具有最大值的所有行。
In [367]: df
Out[367]:
sp mt val 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 dgb 1
6 MM4 S2 rd 2
7 MM4 S2 cb 2
8 MM4 S2 uyi 7
# 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]:
sp mt val count
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
# 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:
您可能不需要这样做groupby()
,但同时使用sort_values
+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
解决方案 5:
在尝试了 Zelazny 建议的解决方案后,我发现它在一个相对较大的 DataFrame(约 40 万行)上非常慢。下面是我发现的另一种方法,它可以在我的数据集上运行得更快。
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']]
解决方案 6:
使用groupby
及idxmax
方法:
将 col 转移
date
到datetime
:
df['date'] = pd.to_datetime(df['date'])
max
获取列的索引date
,之后groupyby ad_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
解决方案 7:
对我来说,最简单的解决方案是当计数等于最大值时保留值。因此,以下一行命令就足够了:
df[df['count'] == df.groupby(['Mt'])['count'].transform(max)]
解决方案 8:
总结一下,方法有很多,但是哪种方法更快呢?
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.10243558883666992秒---
--3b)0.1004343032836914 秒---
--4)0.028397560119628906秒---
--5)0.07552886009216309秒---
解决方案 9:
尝试在 groupby 对象上使用nlargest
。优点是它返回从中提取“第 n 个最大项目”的行,并且我们可以获取它们的索引。
在这种情况下,我们想要n=1
最大值并keep='all'
包含重复的最大值。
注意:我们对索引的最后一个(-1)元素进行切片,因为在这种情况下我们的索引由元组组成(例如('MM1', 'S1', 0)
)。
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(['Sp', 'Mt'])['count'].nlargest(1, keep='all')
df.loc[[i[-1] for i in d.index]]
Sp Mt Val count
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
解决方案 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(['Sp', 'Mt'])
.apply(lambda group: group[group['Count'] == group['Count'].max()])
.reset_index(drop=True))
Sp Mt Val Count
0 MM1 S1 a 3
1 MM1 S3 cb 5
2 MM2 S3 mk 8
3 MM2 S4 bg 10
4 MM4 S2 uyi 7
.reset_index(drop=True)
通过删除组索引让您返回原始索引。
解决方案 11:
意识到将“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
解决方案 12:
如果您对 DataFrame 进行排序,则该顺序将在 groupby 中保留。然后,您可以只抓取第一个或最后一个元素并重置索引。
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:
其中许多都是很好的答案,但为了帮助展示可扩展性,在 280 万行具有不同重复数量的行上显示出一些惊人的差异。对我的数据来说,最快的方法是按排序然后删除重复项(删除除最后一个之外的所有项,这比按降序排序并删除除第一个之外的所有项略快)
按升序排序,删除重复项,保留最后项 (2.22 秒)
降序排序,删除重复项保留第一项 (2.32 秒)
在 loc 函数内变换最大值(3.73 秒)
Transform Max 存储 IDX 然后使用 loc 选择作为第二步(3.84 秒)
使用 Tail 进行分组(8.98 秒)
IDMax 与 groupby 结合,然后使用 loc select 作为第二步(95.39 秒)
IDMax 在 loc 选择中使用 groupby(95.74 秒)
NLargest(1),然后使用 iloc select 作为第二步 (> 35000 s) - 运行一夜后仍未完成
iloc select 中的 NLargest(1)(> 35000 秒)-运行一夜后仍未完成
如您所见,Sort 比 transform 快 1/3,比 groupby 快 75%。其他所有操作都慢 40 倍。在小型数据集中,这可能无关紧要,但如您所见,这会对大型数据集产生重大影响。
解决方案 14:
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'))
解决方案 15:
另一种使用排名的方法
idx = df.groupby(['Sp', 'Mt'])['count'].rank(method="dense", ascending=False)==1
df[idx]
解决方案 16:
df.loc[df.groupby('mt')['count'].idxmax()]
如果df
索引不是唯一的,您可能df.reset_index(inplace=True)
首先需要执行这一步。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件