是否有可能将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]
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
如何以有效的方式基于比较功能删除重复项?
更重要的是,如果我分别使用不同的比较函数进行比较,我该怎么办?
答案 0 :(得分:3)
答案 1 :(得分:3)
IIUC,您的问题是如何使用任意函数来确定什么是重复。为了强调这一点,我们假设如果第一项的总和加上第二项的平方在每种情况下相同,则两个列表是重复的
In [59]: In [118]: df = pd.DataFrame( {'A': [[1,2],[4,1],[2,3]]} )
(请注意,第一个和第二个列表是等效的,但不相同。)
Python通常是prefers key functions to comparison functions,所以在这里我们需要一个函数来说明列表的关键是什么;在这种情况下,它是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]
但是有些人不喜欢这些蒙特卡罗的事情。
答案 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