按 A 列删除重复项,保留 B 列中值最高的行
- 2025-01-03 08:41:00
- admin 原创
- 98
问题描述:
我有一个数据框,在 A 列中有重复值。我想删除重复项,保留 B 列中值最高的行。
因此:
A B
1 10
1 20
2 30
2 40
3 10
应该变成这样:
A B
1 20
2 40
3 10
我猜可能有一个简单的方法可以做到这一点——可能就像在删除重复项之前对 DataFrame 进行排序一样简单——但我不太了解 groupby 的内部逻辑,无法弄清楚。有什么建议吗?
解决方案 1:
这是最后一个。但不是最大值:
In [10]: df.drop_duplicates(subset='A', keep="last")
Out[10]:
A B
1 1 20
3 2 40
4 3 10
您还可以执行类似以下操作:
In [12]: df.groupby('A', group_keys=False).apply(lambda x: x.loc[x.B.idxmax()])
Out[12]:
A B
A
1 1 20
2 2 40
3 3 10
解决方案 2:
最佳答案做了太多工作,对于较大的数据集来说似乎非常慢。apply
很慢,如果可能的话应该避免。ix
已被弃用,也应避免。
df.sort_values('B', ascending=False).drop_duplicates('A').sort_index()
A B
1 1 20
3 2 40
4 3 10
或者简单地按所有其他列进行分组,然后取所需列的最大值。df.groupby('A', as_index=False).max()
解决方案 3:
最简单的解决方案:
要根据一列删除重复项:
df = df.drop_duplicates('column_name', keep='last')
要根据多列删除重复项:
df = df.drop_duplicates(['col_name1','col_name2','col_name3'], keep='last')
解决方案 4:
我会先按 B 列降序对数据框进行排序,然后删除 A 列的重复项并保留第一个
df = df.sort_values(by='B', ascending=False)
df = df.drop_duplicates(subset='A', keep="first")
没有任何 groupby
解决方案 5:
尝试一下:
df.groupby(['A']).max()
解决方案 6:
我是通过一个重复问题的链接来到这里的。
对于只有两列的情况,这样做不是更简单吗:
df.groupby('A')['B'].max().reset_index()
并保留整行(当有更多列时,这就是让我来到这里的“重复问题”所问的):
df.loc[df.groupby(...)[column].idxmax()]
例如,为了保留'C'
取最大值的完整行,对于每组['A', 'B']
,我们可以执行以下操作:
out = df.loc[df.groupby(['A', 'B')['C'].idxmax()]
当组相对较少(即有很多重复项)时,这比drop_duplicates()
解决方案(较少排序)更快:
设置:
n = 1_000_000
df = pd.DataFrame({
'A': np.random.randint(0, 20, n),
'B': np.random.randint(0, 20, n),
'C': np.random.uniform(size=n),
'D': np.random.choice(list('abcdefghijklmnopqrstuvwxyz'), size=n),
})
(添加sort_index()
以确保解决方案平等):
%timeit df.loc[df.groupby(['A', 'B'])['C'].idxmax()].sort_index()
# 101 ms ± 98.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit df.sort_values(['C', 'A', 'B'], ascending=False).drop_duplicates(['A', 'B']).sort_index()
# 667 ms ± 784 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
解决方案 7:
最简单的方法:
# First you need to sort this DF as Column A as ascending and column B as descending
# Then you can drop the duplicate values in A column
# Optional - you can reset the index and get the nice data frame again
# I'm going to show you all in one step.
d = {'A': [1,1,2,3,1,2,3,1], 'B': [30, 40,50,42,38,30,25,32]}
df = pd.DataFrame(data=d)
df
A B
0 1 30
1 1 40
2 2 50
3 3 42
4 1 38
5 2 30
6 3 25
7 1 32
df = df.sort_values(['A','B'], ascending =[True,False]).drop_duplicates(['A']).reset_index(drop=True)
df
A B
0 1 40
1 2 50
2 3 42
解决方案 8:
我认为你的情况其实不需要 groupby。我会按降序对 B 列进行排序,然后将重复项放在 A 列,如果你愿意,还可以有一个新的漂亮而干净的索引,如下所示:
df.sort_values('B', ascending=False).drop_duplicates('A').sort_index().reset_index(drop=True)
解决方案 9:
你也可以尝试一下
df.drop_duplicates(subset='A', keep='last')
我从https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.drop_duplicates.html提到了这一点
解决方案 10:
这是我必须解决的一个值得分享的变体:对于中的每个唯一字符串,columnA
我都想找到中最常见的关联字符串columnB
。
df.groupby('columnA').agg({'columnB': lambda x: x.mode().any()}).reset_index()
.any()
如果众数相同,则选取其中一个。(请注意,在 s 系列上使用会.any()
返回int
布尔值,而不是选取其中之一。)
对于原始问题,相应的方法简化为
df.groupby('columnA').columnB.agg('max').reset_index()
。
解决方案 11:
当已经给出的帖子回答问题时,我做了一些小改动,添加了应用 max() 函数的列名,以提高代码的可读性。
df.groupby('A', as_index=False)['B'].max()
解决方案 12:
与所选答案非常相似的方法,但按多列对数据框进行排序可能是一种更简单的编码方法。
"A"
首先,按和列对日期范围进行排序"B"
,ascending=False
确保从最高值到最低值排序:
df.sort_values(["A", "B"], ascending=False, inplace=True)
然后,删除重复项并仅保留第一个项,该项已经是具有最高值的项目:
df.drop_duplicates(inplace=True)
解决方案 13:
如果您最终到达这里,并且有一个包含几个相等列(其中一些不同)的数据框,并且想要保留原始索引:
df = (df.sort_values('B', ascending=False)
.drop_duplicates(list(final_out_combined.columns.difference(['B'],sort=False)))
.sort_index())
您可以在行中drop_duplicates
添加可以有差异的列,例如:
drop_duplicates(list(final_out_combined.columns.difference(['B', 'C'],sort=False)))
意味着B
不会C
检查重复项。
解决方案 14:
这也有效:
a=pd.DataFrame({'A':a.groupby('A')['B'].max().index,'B':a.groupby('A') ['B'].max().values})
解决方案 15:
我不会给你整个答案(无论如何我不认为你正在寻找解析和写入文件部分),但一个关键的提示就足够了:使用 python 的set()
函数,然后sorted()
或.sort()
加上.reverse()
:
>>> a=sorted(set([10,60,30,10,50,20,60,50,60,10,30]))
>>> a
[10, 20, 30, 50, 60]
>>> a.reverse()
>>> a
[60, 50, 30, 20, 10]