pandas drop_duplicates 使用比较函数

des*_*ato 5 python pandas

是否可以以某种方式将pandas.drop_duplicates与比较运算符一起使用,该比较运算符比较特定列中的两个对象以识别重复项?如果不是,还有什么替代方案?

这是一个可以使用它的示例:

我有一个 pandas DataFrame,其中列出了特定列中的值,我希望根据列删除重复项A

import pandas as pd

df = pd.DataFrame( {'A': [[1,2],[2,3],[1,2]]} )
print df
Run Code Online (Sandbox Code Playgroud)

给我

        A
0  [1, 2]
1  [2, 3]
2  [1, 2]
Run Code Online (Sandbox Code Playgroud)

使用pandas.drop_duplicates

df.drop_duplicates( 'A' )
Run Code Online (Sandbox Code Playgroud)

给我一个TypeError

[...]
TypeError: type object argument after * must be a sequence, not itertools.imap
Run Code Online (Sandbox Code Playgroud)

然而我想要的结果是

        A
0  [1, 2]
1  [2, 3]
Run Code Online (Sandbox Code Playgroud)

我的比较函数在这里:

def cmp(x,y):
    return x==y
Run Code Online (Sandbox Code Playgroud)

但原则上它可能是别的东西,例如,

def cmp(x,y):
    return x==y and len(x)>1
Run Code Online (Sandbox Code Playgroud)

如何根据比较函数有效地删除重复项?

更重要的是,如果我有更多列要分别使用不同的比较函数进行比较,我该怎么办?

Ami*_*ory 6

IIUC,你的问题是如何使用任意函数来确定什么是重复的。为了强调这一点,假设两个列表是重复的,如果第一项的总和加上第二项的平方在每种情况下都相同

In [59]: In [118]: df = pd.DataFrame( {'A': [[1,2],[4,1],[2,3]]} )
Run Code Online (Sandbox Code Playgroud)

(请注意,第一个和第二个列表是等效的,但不相同。)

Python 通常更喜欢键函数而不是比较函数,所以这里我们需要一个函数来说明列表的键是什么;在这种情况下,它是lambda l: l[0] + l[1]**2

我们可以使用groupby+first按键函数的值进行分组,然后取每组的第一个:

In [119]: df.groupby(df.A.apply(lambda l: l[0] + l[1]**2)).first()
Out[119]: 
         A
A         
5   [1, 2]
11  [2, 3]
Run Code Online (Sandbox Code Playgroud)

编辑

在对问题进行进一步编辑后,这里有一些使用的示例

df = pd.DataFrame( {'A': [[1,2],[2,3],[1,2], [1], [1], [2]]} )
Run Code Online (Sandbox Code Playgroud)

那么对于

def cmp(x,y):
    return x==y
Run Code Online (Sandbox Code Playgroud)

这可能是

In [158]: df.groupby(df.A.apply(tuple)).first()
Out[158]: 
             A
A             
(1,)       [1]
(1, 2)  [1, 2]
(2,)       [2]
(2, 3)  [2, 3]
Run Code Online (Sandbox Code Playgroud)

为了

def cmp(x,y):
     return x==y and len(x)>1
Run Code Online (Sandbox Code Playgroud)

这可能是

In [184]: class Key(object):
   .....:     def __init__(self):
   .....:         self._c = 0
   .....:     def __call__(self, l):
   .....:         if len(l) < 2:
   .....:             self._c += 1
   .....:             return self._c
   .....:         return tuple(l)
   .....:     

In [187]: df.groupby(df.A.apply(Key())).first()
Out[187]: 
             A
A             
1          [1]
2          [1]
3          [2]
(1, 2)  [1, 2]
(2, 3)  [2, 3]
Run Code Online (Sandbox Code Playgroud)

或者,这也可以通过更简洁地完成

In [190]: df.groupby(df.A.apply(lambda l: np.random.rand() if len(l) < 2 else tuple(l))).first()
Out[190]: 
                     A
A                     
0.112012068449     [2]
0.822889598152     [1]
0.842630848774     [1]
(1, 2)          [1, 2]
(2, 3)          [2, 3]
Run Code Online (Sandbox Code Playgroud)

但有些人不喜欢这些蒙特卡洛的东西。