Pandas的drop_duplicates方法在包含列表的数据框上无法正常工作。

53

我想在数据框上使用drop_duplicates方法,但是却出现了错误。如下所示:

错误:TypeError: unhashable type: 'list'

我使用的代码:

df = db.drop_duplicates()

我的数据库很大,包含字符串、浮点数、日期、NaN、布尔值、整数... 任何帮助都将不胜感激。


1
显然,它包含了列表,这是导致错误的原因。通常情况下,我认为一个由列表组成的DataFrame是代码异味... - juanpa.arrivillaga
3
我知道这是一段时间以前的事情了,但是否可以详细说明为什么包含列表的df是一种代码异味? - KubiK888
4个回答

63

drop_duplicates不能像错误信息所示那样处理数据框中的列表。但是,您可以在转换为str类型的数据框上删除重复项,然后使用结果中的索引从原始数据框中提取行。

设置

df = pd.DataFrame({'Keyword': {0: 'apply', 1: 'apply', 2: 'apply', 3: 'terms', 4: 'terms'},
 'X': {0: [1, 2], 1: [1, 2], 2: 'xy', 3: 'xx', 4: 'yy'},
 'Y': {0: 'yy', 1: 'yy', 2: 'yx', 3: 'ix', 4: 'xi'}})

#Drop directly causes the same error
df.drop_duplicates()
Traceback (most recent call last):
...
TypeError: unhashable type: 'list'

解决方案

#convert hte df to str type, drop duplicates and then select the rows from original df.

df.loc[df.astype(str).drop_duplicates().index]
Out[205]: 
  Keyword       X   Y
0   apply  [1, 2]  yy
2   apply      xy  yx
3   terms      xx  ix
4   terms      yy  xi

#the list elements are still list in the final results.
df.loc[df.astype(str).drop_duplicates().index].loc[0,'X']
Out[207]: [1, 2]

编辑:用 loc 替换了 iloc。在这种特殊情况下,两者都可以作为索引匹配位置索引,但不是普遍情况。


@Allen 你怎么在StackOverflow上添加Ipython代码块?我在网上搜寻了很多但一直没有找到好的解决方法。 - Madhi
1
这个答案并不考虑同一列中不同行的两个列表包含相同元素但顺序不同的情况。我猜这也取决于用户是否希望将具有相同元素但顺序不同的列表视为重复项。 - PSK

19

@Allen的答案很棒,但有一点小问题。

df.iloc[df.astype(str).drop_duplicates().index]

应该使用loc而不是iloc,请看示例。

a = pd.DataFrame([['a',18],['b',11],['a',18]],index=[4,6,8])
Out[52]: 
   0   1
4  a  18
6  b  11
8  a  18

a.iloc[a.astype(str).drop_duplicates().index]
Out[53]:
...
IndexError: positional indexers are out-of-bounds

a.loc[a.astype(str).drop_duplicates().index]
Out[54]: 
   0   1
4  a  18
6  b  11

5

我还想提醒一下(如果有人像我一样傻),如果你错误地将一个列表的列表作为 drop_duplicates 函数的 'subset' 参数,你将会得到相同的错误。

结果发现我花了几个小时去寻找一个我的数据框中没有的列表,只是因为我在参数中多加了一些方括号。


1
概述:您可以查看哪些行是重复的。
方法1:
df2=df.copy()
mylist=df2.iloc[0,1]
df2.iloc[0,1]=' '.join(map(str,mylist))

mylist=df2.iloc[1,1]
df2.iloc[1,1]=' '.join(map(str,mylist))

duplicates=df2.duplicated(keep=False)
print(df2[duplicates])

方法2:
print(df.astype(str).duplicated(keep=False))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接