Pandas删除两列中反向的重复项



一个示例DataFrame:

df = pd.DataFrame({'node_a': ['X', 'X', 'X', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z'],
'node_b': ['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z'],
'value':  [  2,   8,   1,   8,   7,   3,   1,   3,   2]})
node_a  node_b  value
0   X       X       2
1   X       Y       8
2   X       Z       1
3   Y       X       8
4   Y       Y       7
5   Y       Z       3
6   Z       X       1
7   Z       Y       3
8   Z       Z       2

我需要删除反向重复项,例如保持node_a='X',node_b='Y',但删除node_a='Y'和node_b='X'。

期望输出:

node_a  node_b  value
0   X       X       2
1   X       Y       8
2   X       Z       1
4   Y       Y       7
5   Y       Z       3
8   Z       Z       2

请注意,我需要一个通用的解决方案,而不是针对这个实际数据。

让我们使用np.sortaxis=1node_anode_b进行排序,并将这些排序列分配给数据帧,然后使用数据帧上的drop_duplicates根据这些分配列删除数据帧中的重复条目:

df[['x', 'y']] = np.sort(df[['node_a', 'node_b']], axis=1)
out = df.drop_duplicates(['x', 'y']).drop(['x', 'y'], 1)

结果:

print(out)
node_a node_b  value
0      X      X      2
1      X      Y      8
2      X      Z      1
4      Y      Y      7
5      Y      Z      3
8      Z      Z      2

您可以执行以下操作:

# duplicates regardless the order
un_dups = pd.Series([frozenset(row) for row in df[['node_a', 'node_b']].to_numpy()]).duplicated()
# duplicates with the same order
o_dups = df.duplicated(subset=['node_a', 'node_b'])
# keep only those that are not duplicates with reverse order xor
mask = ~(un_dups ^ o_dups)
print(df[mask])

输出

node_a node_b  value
0      X      X      2
1      X      Y      8
2      X      Z      1
4      Y      Y      7
5      Y      Z      3
8      Z      Z      2

其想法是创建一个掩码,如果您是按相反顺序复制的,则该掩码将为False。

要更好地理解该方法,请查看真相值:

node_a node_b  value  un_dups  o_dups    xor
0      X      X      2    False   False  False
1      X      Y      8    False   False  False
2      X      Z      1    False   False  False
3      Y      X      8     True   False   True
4      Y      Y      7    False   False  False
5      Y      Z      3    False   False  False
6      Z      X      1     True   False   True
7      Z      Y      3     True   False   True
8      Z      Z      2    False   False  False

正如您所看到的,xor(exclusive or(表明,只要输入不同,它的输出都是true。假设一个有序重复的值在无序时也会重复,那么只有当列中的值按相反顺序重复时,xor才为真。

最后请注意,掩码是xor的否定,即那些不重复的值。

这里有一种方法,包括创建一个新的临时列,对每行中node_a和node_b的顺序进行排序,然后删除重复项,保留排序的第一个实例:

df['sorted'] = df.apply(lambda x: ''.join(sorted([x['node_a'],x['node_b']])),axis=1)
#   node_a node_b  value sorted
# 0      X      X      2     XX
# 1      X      Y      8     XY
# 2      X      Z      1     XZ
# 3      Y      X      8     XY
# 4      Y      Y      7     YY
# 5      Y      Z      3     YZ
# 6      Z      X      1     XZ
# 7      Z      Y      3     YZ
# 8      Z      Z      2     ZZ
df.drop_duplicates(subset='sorted').drop('sorted',axis=1)
#   node_a node_b  value
# 0      X      X      2
# 1      X      Y      8
# 2      X      Z      1
# 4      Y      Y      7
# 5      Y      Z      3
# 8      Z      Z      2

最新更新