基于附加列优先级过滤pandas数据框中的重复项

2 投票
3 回答
4741 浏览
提问于 2025-04-18 15:07

我想从一个数据表中筛选出在X列中有重复的行。不过,如果X列中有重复的值,我希望根据另一个Y列的值来优先选择其中一个。例如:

import pandas as pd
print pd.__version__
x = pd.DataFrame([
    ['best', 'a', 'x'],
    ['worst', 'b', 'y'],
    ['best', 'c', 'x'],
    ['worst','d', 'y'],
    ['best','d', 'y'],
    ['worst','d', 'y'],
    ['best','d', 'z'],
    ['best','d', 'z'],
], columns=['a', 'b', 'c'])
print x
x.drop_duplicates(cols='c', inplace=True)
print x

       a  b  c
0   best  a  x
1  worst  b  y
2   best  c  x
3  worst  d  y
4   best  d  y
5  worst  d  y
6   best  d  z
7   best  d  z

       a  b  c
0   best  a  x
1  worst  b  y
6   best  d  z

我想优先选择在a列中值为best的重复项。这样会得到以下结果:

       a  b  c
0   best  a  x
4   best  d  y
6   best  d  z

有没有人知道在pandas中怎么正确地做到这一点?有没有比单纯排序行更通用的方法,这样可以只保留重复项中的第一个出现?

3 个回答

2

根据@Paul H的做法(他在PyData邮件列表中提到,GroupBy.filter似乎存在一个奇怪的bug,导致某些原因下y被排除在外):

In [31]: df
Out[31]:
       a  b  c
0   best  a  x
1  worst  b  y
2   best  c  x
3   best  d  y
4  worst  d  y
5  worst  d  y
6   best  d  z

In [32]: besties = pd.concat(v[v.a == 'best'] for _, v in df.groupby('c'))

In [33]: besties
Out[33]:
      a  b  c
0  best  a  x
2  best  c  x
3  best  d  y
6  best  d  z

In [34]: res = besties.drop_duplicates(subset=['c'])

In [35]: res
Out[35]:
      a  b  c
0  best  a  x
3  best  d  y
6  best  d  z
2

我觉得用两个 groupby 语句可以帮你实现你想要的效果。这里有一些稍微修改过的输入数据:

x = pd.DataFrame([
    ['best', 'a', 'x'],
    ['worst', 'b', 'y'],
    ['best', 'c', 'x'],
    ['worst','d', 'y'],
    ['worst','d', 'y'],
    ['best','d', 'y'],
    ['best','d', 'z'],
    ['best','d', 'z'],
], columns=['a', 'b', 'c'])

x.groupby(by=['c']) \
 .filter(lambda g: g['a'] == 'best') \
 .groupby(by=['b'], as_index=False) \
 .first() \
 .sort(axis=1)  # the columns get out of order in the second groupby

这段代码返回的是:

   b     a  c
0  a  best  x
1  c  best  x
2  d  best  z

不过,关于你的例子输入和输出,还是不太清楚具体应该怎么处理。但我觉得我们已经接近答案了。

5

我觉得一个更简单的方法是先对数据表进行排序,然后去掉重复的项,只保留第一个。这种方法很可靠(这里的'a'是一个包含两个值的字符串,但如果有更多字符串值需要排序,你可以使用一个函数把字符串转换成整数列)。

x = x.sort_values(['a']).drop_duplicates(cols='c')

撰写回答