问题 熊猫:删除所有重复索引的记录


我有一个数据集,可能有重复的标识符记录 appkey。理想情况下,重复的记录应该不存在,因此我将它们视为数据收集错误。我需要删除所有的实例 appkey 这不止一次发生。

drop_duplicates 方法在这种情况下是无用的(或者是?),因为它要么选择第一个或最后一个重复项。是否有任何明显的成语用熊猫实现这一目标?


6341
2017-09-17 13:29


起源



答案:


截至pandas版本0.12,我们有 filter 为了这。它完全符合@Andy的解决方案所使用的功能 transform,但更简洁,更快一些。

df.groupby('AppKey').filter(lambda x: x.count() == 1)

窃取@Andy的例子,

In [1]: df = pd.DataFrame([[1, 2], [1, 4], [5, 6]], columns=['AppKey', 'B'])

In [2]: df.groupby('AppKey').filter(lambda x: x.count() == 1)
Out[2]: 
   AppKey  B
2       5  6

7
2017-09-17 14:18



这正是我尝试和失败的原因。谢谢你。 - asb
就像我说的,这就是我的尝试。但我得到这个错误: TypeError: 'function' object is not iterable。有任何想法吗?我知道我在这里真的很懒。对不起。 - asb
能给我看看么 pd.__version__? - Dan Allan
啊,废话! pandas.__version__ 是0.10.1。我应该自言自语。 - asb
哈哈哈,当我意识到这个属于Team Filter时,我正要祝贺你加入Team Transform。 : - D. - Dan Allan


答案:


截至pandas版本0.12,我们有 filter 为了这。它完全符合@Andy的解决方案所使用的功能 transform,但更简洁,更快一些。

df.groupby('AppKey').filter(lambda x: x.count() == 1)

窃取@Andy的例子,

In [1]: df = pd.DataFrame([[1, 2], [1, 4], [5, 6]], columns=['AppKey', 'B'])

In [2]: df.groupby('AppKey').filter(lambda x: x.count() == 1)
Out[2]: 
   AppKey  B
2       5  6

7
2017-09-17 14:18



这正是我尝试和失败的原因。谢谢你。 - asb
就像我说的,这就是我的尝试。但我得到这个错误: TypeError: 'function' object is not iterable。有任何想法吗?我知道我在这里真的很懒。对不起。 - asb
能给我看看么 pd.__version__? - Dan Allan
啊,废话! pandas.__version__ 是0.10.1。我应该自言自语。 - asb
哈哈哈,当我意识到这个属于Team Filter时,我正要祝贺你加入Team Transform。 : - D. - Dan Allan


这是一种方式,使用 转变 有计数:

In [1]: df = pd.DataFrame([[1, 2], [1, 4], [5, 6]], columns=['AppKey', 'B'])

In [2]: df
Out[2]:
   AppKey  B
0       1  2
1       1  4
2       5  6

通过AppKey列进行分组并应用转换计数,意味着计算每次出现的AppKey,并将计数分配给出现的那些行:

In [3]: count_appkey = df.groupby('AppKey')['AppKey'].transform('count')

In [4]: count_appkey
Out[4]:
0    2
1    2
2    1
Name: AppKey, dtype: int64

In [5]: count_appkey == 1
Out[5]:
0    False
1    False
2     True
Name: AppKey, dtype: bool

然后,您可以将其用作原始DataFrame的布尔掩码(仅保留AppKey恰好出现一次的那些行):

In [6]: df[count_appkey == 1]
Out[6]:
   AppKey  B
2       5  6

6
2017-09-17 14:09



非常感谢安迪。 - asb


在pandas版本0.17中,drop_duplicates函数有一个'keep'参数,可以设置为'False'以保持没有重复的条目(其他选项是keep ='first'和keep ='last')。所以,在这种情况下:

df.drop_duplicates(subset=['appkey'],keep=False)

2
2017-10-28 11:09





以下解决方案使用 设定运作 适合我。它的速度要快得多,但速度要快一些 filter 解:

In [1]: import pandas as pd
In [2]: def dropalldups(df, key):
   ...:     first = df.duplicated(key)  # really all *but* first
   ...:     last = df.duplicated(key, take_last=True)
   ...:     return df.reindex(df.index - df[first | last].index)
   ...: 
In [3]: df = pd.DataFrame([[1, 2], [1, 4], [5, 6]], columns=['AppKey', 'B'])
In [4]: dropalldups(df, 'AppKey')
Out[4]: 
   AppKey  B
2       5  6

[1 rows x 2 columns]
In [5]: %timeit dropalldups(df, 'AppKey')
1000 loops, best of 3: 379 µs per loop
In [6]: %timeit df.groupby('AppKey').filter(lambda x: x.count() == 1)
1000 loops, best of 3: 1.57 ms per loop

在较大的数据集上,性能差异更加显着。以下是具有44k行的DataFrame的结果。我正在过滤的列是一个6个字符的字符串。有870次出现560个重复值:

In [94]: %timeit dropalldups(eq, 'id')
10 loops, best of 3: 26.1 ms per loop
In [95]: %timeit eq.groupby('id').filter(lambda x: x.count() == 1)
1 loops, best of 3: 13.1 s per loop

1
2018-04-08 12:07



哇,很长一段时间后我回到了这个结果。这确实是戏剧性的。谢谢。 - asb