python pandas:删除列A的重复项,保持列B中具有最高值的行

Abe*_*Abe 117 python duplicates pandas

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

所以这:

A B
1 10
1 20
2 30
2 40
3 10
Run Code Online (Sandbox Code Playgroud)

应该变成这样:

A B
1 20
2 40
3 10
Run Code Online (Sandbox Code Playgroud)

Wes添加了一些很好的功能来删除重复项:http://wesmckinney.com/blog/?p = 340 .但是AFAICT,它是专为完全重复而设计的,所以没有提到选择保留哪些行的标准.

我猜这可能是一种简单的方法 - 可能就像在删除重复项之前对数据帧进行排序一样简单 - 但我不知道groupby的内部逻辑是否足够清楚.有什么建议?

Wes*_*ney 145

这需要最后一次.虽然不是最大值:

In [10]: df.drop_duplicates(subset='A', keep="last")
Out[10]: 
   A   B
1  1  20
3  2  40
4  3  10
Run Code Online (Sandbox Code Playgroud)

你也可以这样做:

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
Run Code Online (Sandbox Code Playgroud)

  • 小注意:`cols`和`take_last`参数是折旧的,并且已被`subset`和`keep`参数替换.http://pandas.pydata.org/pandas-docs/version/0.17.1/generated/pandas.DataFrame.drop_duplicates.html (12认同)
  • 这个答案现在已经过时了.请参阅下面的@Ted Petrou的答案. (4认同)
  • 是否有理由不使用 `df.sort_values(by=['B']).drop_duplicates(subset=['A'], keep='last')`?我的意思是这个 sort_values 对我来说似乎是安全的,但我不知道它是否真的是。 (2认同)

Ted*_*rou 59

最重要的答案是做了太多的工作,对于大型数据集看起来非常慢.apply很慢,应该尽可能避免.ix不推荐使用,也应该避免使用.

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

   A   B
1  1  20
3  2  40
4  3  10
Run Code Online (Sandbox Code Playgroud)

或者只是按所有其他列分组,并获取所需列的最大值. df.groupby('A', as_index=False).max()

  • 这实际上是一种切肉刀的方法。我想知道是否可以通过在删除时使用一些“lamba”函数来概括它。例如,我怎样才能只删除小于这些重复值的平均值的值。 (3认同)

Nob*_*bel 13

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

df = df.sort_values(by='B', ascending=False)
df = df.drop_duplicates(subset='A', keep="first")
Run Code Online (Sandbox Code Playgroud)

没有任何分组


Pie*_*e D 9

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

\n

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

\n
df.groupby(\'A\')[\'B\'].max().reset_index()\n
Run Code Online (Sandbox Code Playgroud)\n

并保留一整行(当有更多列时,这就是让我来到这里的“重复问题”所问的):

\n
df.loc[df.groupby(...)[column].idxmax()]\n
Run Code Online (Sandbox Code Playgroud)\n

例如,要保留\'C\'取最大值的整行,对于每组[\'A\', \'B\'],我们将执行以下操作:

\n
out = df.loc[df.groupby([\'A\', \'B\')[\'C\'].idxmax()]\n
Run Code Online (Sandbox Code Playgroud)\n

当组相对较少(即有大量重复项)时,这比drop_duplicates() 解决方案(较少排序)更快:

\n

设置:

\n
n = 1_000_000\ndf = pd.DataFrame({\n    \'A\': np.random.randint(0, 20, n),\n    \'B\': np.random.randint(0, 20, n),\n    \'C\': np.random.uniform(size=n),\n    \'D\': np.random.choice(list(\'abcdefghijklmnopqrstuvwxyz\'), size=n),\n})\n
Run Code Online (Sandbox Code Playgroud)\n

(添加sort_index()以确保解相等):

\n
%timeit df.loc[df.groupby([\'A\', \'B\'])[\'C\'].idxmax()].sort_index()\n# 101 ms \xc2\xb1 98.7 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n\n%timeit df.sort_values([\'C\', \'A\', \'B\'], ascending=False).drop_duplicates([\'A\', \'B\']).sort_index()\n# 667 ms \xc2\xb1 784 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n
Run Code Online (Sandbox Code Playgroud)\n


Gil*_*gio 8

最简单的解决方案:

要基于一列删除重复项:

df = df.drop_duplicates('column_name', keep='last')
Run Code Online (Sandbox Code Playgroud)

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

df = df.drop_duplicates(['col_name1','col_name2','col_name3'], keep='last')
Run Code Online (Sandbox Code Playgroud)

  • 但 OP 希望保留 B 列中的最高值。如果您先排序,这可能会起作用。但这基本上就是泰德·彼得鲁的答案。 (4认同)
  • 此答案假设列已排序,但问题中未指定。 (4认同)

eum*_*iro 6

试试这个:

df.groupby(['A']).max()
Run Code Online (Sandbox Code Playgroud)

  • 整齐.如果数据帧包含更多列(例如C,D,E)怎么办?在这种情况下,Max似乎不起作用,因为我们需要指定B是唯一需要最大化的列. (4认同)

rra*_*rra 5

最简单的方法是:

# 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
Run Code Online (Sandbox Code Playgroud)