249

我在 A 列中有一个具有重复值的数据框。我想删除重复项,将具有最高值的行保留在 B 列中。

所以这:

A B
1 10
1 20
2 30
2 40
3 10

应该变成这样:

A B
1 20
2 40
3 10

我猜可能有一种简单的方法可以做到这一点——也许就像在删除重复项之前对 DataFrame 进行排序一样简单——但我不太了解 groupby 的内部逻辑来弄清楚它。有什么建议么?

4

13 回答 13

293

这是最后一个。虽然不是最大值:

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
于 2012-10-25T00:10:02.923 回答
132

最重要的答案是做太多的工作,而且对于更大的数据集看起来很慢。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()

于 2017-01-14T14:04:49.037 回答
38

最简单的解决方案:

要基于一列删除重复项:

df = df.drop_duplicates('column_name', keep='last')

要删除基于多列的重复项:

df = df.drop_duplicates(['col_name1','col_name2','col_name3'], keep='last')
于 2019-03-06T11:13:47.833 回答
18

我将首先使用 B 列降序对数据框进行排序,然后删除 A 列的重复项并首先保留

df = df.sort_values(by='B', ascending=False)
df = df.drop_duplicates(subset='A', keep="first")

没有任何 groupby

于 2020-03-18T10:46:25.693 回答
11

试试这个:

df.groupby(['A']).max()
于 2012-09-19T15:10:56.213 回答
4

我认为在您的情况下,您实际上并不需要 groupby。我会按 B 列的降序排序,然后在 A 列删除重复项,如果你愿意,你还可以有一个新的漂亮和干净的索引,如下所示:

df.sort_values('B', ascending=False).drop_duplicates('A').sort_index().reset_index(drop=True)
于 2017-09-01T11:15:59.983 回答
4

我是通过重复问题的链接被带到这里的。

对于只有两列,做起来会不会更简单:

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)
于 2021-08-21T20:49:38.230 回答
2

你也可以试试这个

df.drop_duplicates(subset='A', keep='last')

我从https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.drop_duplicates.html引用了这个

于 2017-05-27T13:30:04.787 回答
2

这是我必须解决的一个值得分享的变体:对于中的每个唯一字符串,columnA我想在columnB.

df.groupby('columnA').agg({'columnB': lambda x: x.mode().any()}).reset_index()

如果该.any()模式有平局,则选择一个。(请注意,.any()在一系列ints 上使用会返回一个布尔值,而不是选择其中一个。)

对于原始问题,相应的方法简化为

df.groupby('columnA').columnB.agg('max').reset_index().

于 2019-09-20T17:25:53.307 回答
2

最简单的方法:

# 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
于 2020-05-22T03:33:00.827 回答
0

当已经给出的帖子回答了这个问题时,我通过添加应用 max() 函数的列名进行了一个小的更改,以提高代码的可读性。

df.groupby('A', as_index=False)['B'].max()
于 2018-06-24T11:34:45.183 回答
-1

这也有效:

a=pd.DataFrame({'A':a.groupby('A')['B'].max().index,'B':a.groupby('A')       ['B'].max().values})
于 2017-01-14T15:16:38.880 回答
-9

我不会给你完整的答案(我不认为你正在寻找解析和写入文件部分),但一个关键的提示就足够了:使用 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]
于 2012-09-19T15:03:40.067 回答