按列A删除重复项,保留列B中值最高的行

我有一个在列a中具有重复值的数据帧,我想删除重复项,保持列B中值最高的行。

所以这个:

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

应该变成这样:

A B
1 20
2 40
3 10

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

371915 次浏览

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

试试这个:

df.groupby(['A']).max()

这是最后一个。但不是最大值:

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

最上面的答案是做了太多的工作,对于更大的数据集看起来非常慢。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()

这也是可行的:

a=pd.DataFrame({'A':a.groupby('A')['B'].max().index,'B':a.groupby('A')       ['B'].max().values})

你也可以试试这个

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

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

我认为在你的情况下,你真的不需要groupby。我会按B列降序排序,然后在A列删除重复项如果你愿意,你也可以有一个新的nice and

df.sort_values('B', ascending=False).drop_duplicates('A').sort_index().reset_index(drop=True)

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

df.groupby('A', as_index=False)['B'].max()

最简单的解决方案:

删除基于一列的重复项:

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

删除基于多个列的重复数据。

df = df.drop_duplicates(['col_name1','col_name2','col_name3'], keep='last')

这里有一个我必须解决的值得分享的变化:对于columnA中的每个唯一字符串,我想找到columnB中最常见的关联字符串。

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

.any()会在模式相同的情况下选择一个。(注意,在一系列__abc2上使用.any()将返回一个布尔值,而不是从中选择一个。)

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

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

我将首先对数据帧进行排序,列B降序,然后删除列A的重复项并保持优先

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

没有任何分组

最简单的方法是:

# 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

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

对于只有两列,这样做不是更简单吗:

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)

与所选答案非常相似的方法,但是按多列对数据帧进行排序可能是一种更简单的编码方法。

首先,通过"A""B"列对日期帧进行排序,ascending=False确保它的排名从最高值到最低:

df.sort_values(["A", "B"], ascending=False, inplace=True)

然后,删除重复项,只保留第一项,它已经是值最高的项:

df.drop_duplicates(inplace=True)