繁体   English   中英

pandas drop_duplicates使用比较功能

[英]pandas drop_duplicates using comparison function

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

以下是可以使用它的示例:

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

import pandas as pd

df = pd.DataFrame( {'A': [[1,2],[2,3],[1,2]]} )
print df

给我

        A
0  [1, 2]
1  [2, 3]
2  [1, 2]

使用pandas.drop_duplicates

df.drop_duplicates( 'A' )

给了我一个TypeError

[...]
TypeError: type object argument after * must be a sequence, not itertools.imap

但是,我想要的结果是

        A
0  [1, 2]
1  [2, 3]

我的比较函数将在这里:

def cmp(x,y):
    return x==y

但原则上它可能是其他东西,例如,

def cmp(x,y):
    return x==y and len(x)>1

如何以有效的方式基于比较功能删除重复项?

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

选项1

df[~pd.DataFrame(df.A.values.tolist()).duplicated()]

在此输入图像描述

选项2

df[~df.A.apply(pd.Series).duplicated()]

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

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

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

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]

编辑

在进一步编辑问题之后,这里有一些使用的例子

df = pd.DataFrame( {'A': [[1,2],[2,3],[1,2], [1], [1], [2]]} )

然后为

def cmp(x,y):
    return x==y

这可能是

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]

对于

def cmp(x,y):
     return x==y and len(x)>1

这可能是

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]

或者,这也可以通过更简洁的方式完成

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]

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

Lists本质上是不可取的。 尝试将它们转换为可混合类型(如tuples ,然后您可以继续使用drop_duplicates

df['A'] = df['A'].map(tuple)
df.drop_duplicates('A').applymap(list)

图片


使用函数实现它的一种方法是基于计算系列对象的value_counts ,因为重复的值被聚合,我们只对index部分(顺便说一句是唯一的)而不是实际的计数部分感兴趣。

def series_dups(col_name):
    ser = df[col_name].map(tuple).value_counts(sort=False)
    return (pd.Series(data=ser.index.values, name=col_name)).map(list)

series_dups('A')

0    [1, 2]
1    [2, 3]
Name: A, dtype: object

如果您不想将值转换为tuple ,而是按原样处理值,则可以执行以下操作:

玩具数据:

df = pd.DataFrame({'A': [[1,2], [2,3], [1,2], [3,4]], 
                   'B': [[10,11,12], [11,12], [11,12,13], [10,11,12]]})
df

图片

def series_dups_hashable(frame, col_names):
    for col in col_names:
        ser, indx = np.unique(frame[col].values, return_index=True)
        frame[col] = pd.Series(data=ser, index=indx, name=col)
    return frame.dropna(how='all')

series_dups_hashable(df, ['A', 'B'])   # Apply to subset/all columns you want to check

图片

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM