12

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

drop_duplicates方法在这种情况下没有用(或者是吗?),因为它要么选择第一个或最后一个重复项。有没有明显的习惯用熊猫来实现这一点?

4

4 回答 4

8

从 pandas 0.12 版开始,我们就有filter了这个功能。它完全符合@Andy 的解决方案 using 的功能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
于 2013-09-17T14:18:38.723 回答
7

这是一种方法,使用带计数的转换:

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
于 2013-09-17T14:09:57.407 回答
2

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

df.drop_duplicates(subset=['appkey'],keep=False)
于 2015-10-28T11:09:54.860 回答
1

以下使用集合操作的解决方案对我有用。它比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 个字符的字符串。560 个重复值出现 870 次:

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
于 2014-04-08T12:07:58.820 回答