有没有办法根据不可散列的列删除重复的行?

数据挖掘 Python 熊猫 数据框
2022-02-24 16:30:39

我有一个熊猫数据框 df,其中一列 z 填充了设定值

我想删除重复的行,当它们具有相同的列 z 值(它们是集合)时,2 行被认为是彼此的重复版本。

import pandas as pd

lnks = [ ( 'a' , 'b' , { 'a' , 'b' } ) , ( 'b' , 'c' , { 'b' , 'c' } ) , ( 'b' , 'a' , { 'a' , 'b' } ) ]
lbls = [ 'x' , 'y' , 'z' ]
df = pd.DataFrame.from_records( lnks , columns = lbls )

尝试根据列 z 值删除重复的行:

df.drop_duplicates( subset = 'z' , keep='first')

我收到错误消息:

TypeError: unhashable type: 'set'

有没有办法根据不可散列的类型列删除重复的行?

2个回答

确实,集合是不可散列的(它不能用作散列图(也称为字典)中的键)。因此,您可以做的就是将该列转换为可散列的类型 - 我会选择tuple.

我创建了一个新列,它只是"z"您拥有的列,转换为元组。然后您可以在新列上使用您尝试过的相同方法:

In [1] : import pandas as pd 
    ...:  
    ...: lnks = [ ( 'a' , 'b' , { 'a' , 'b' } ) , ( 'b' , 'c' , { 'b' , 'c' } ) 
    ...: , ( 'b' , 'a' , { 'a' , 'b' } ) ] 
    ...: lbls = [ 'x' , 'y' , 'z' ] 
    ...: df = pd.DataFrame.from_records( lnks , columns = lbls)                 

In [2]: df["z_tuple"] = df.z.apply(lambda x: tuple(x))                         

In [3]: df.drop_duplicates(subset="z_tuple", keep="first")                     
Out[3]: 
   x  y       z z_tuple
0  a  b  {b, a}  (b, a)
1  b  c  {c, b}  (c, b)

apply方法允许您将函数应用于列中的每个项目,然后将值作为新列(Pandas Series 对象)返回。这使您可以像我一样将其作为新列分配回原始 DataFrame。

"z_tuple"如果不再需要,您也可以删除该列:

In [4] : df.drop("z_tuple", axis=1, inplace=True)                               

In [5] : df                                                                     
Out[5] : 
   x  y       z
0  a  b  {b, a}
1  b  c  {c, b}
2  b  a  {b, a}

我不得不承认我没有提到我试图根据包含设置值的列删除重复行的原因。原因是 set { 'a' , 'b' } 与 { 'b' , 'a' } 相同,因此对于 set 列,2 个明显不同的行被认为是相同的,然后被去重......但是这个不可能,因为集合是不可散列的(如 list )

元组是可散列的,但它们元素的顺序很重要......所以当我为每一行构建元组时,我对它们进行排序:

import pandas as pd

lnks = [ ( 'a' , 'b' ) , ( 'b' , 'c' ) , ( 'b' , 'a' ) , ( 'a' , 'd' ) , ( 'd' , 'e' ) ]
lbls = [ 'x' , 'y' ]
df = pd.DataFrame.from_records( lnks , columns = lbls )

构建元组列(每个元组都排序):

df[ 'z' ] = df.apply( lambda d : tuple( sorted( [ d[ 'x' ]  , d[ 'y' ] ] ) ) , axis = 1 )

使用新的元组列删除重复的行(保持第一次出现):

df.drop_duplicates(subset="z", keep="first" , inplace = True )