我有以下 pandas DataFrame 在 A-B-E 和 C-D-F 之间有“镜像复制”行:
import numpy as np
import pandas as pd
df1 = pd.DataFrame(np.array([[1, 2, 3, 4, 47, 27], [5, 6, 7, 8, 21, 40], [9, 10, 11, 12, 45, 33],
[3, 4, 1, 2, 27, 47], [7, 8, 5, 6, 40, 21], [11, 12, 9, 10, 33, 45]]),
columns=['A', 'B', 'C', 'D', 'E', 'F'])
print(df1)
## A B C D E F
## 0 1 2 3 4 47 27
## 1 5 6 7 8 21 40
## 2 9 10 11 12 45 33
## 3 3 4 1 2 27 47
## 4 7 8 5 6 40 21
## 5 11 12 9 10 33 45
所谓“镜像副本”,我的意思是:如果您查看第 3、4、5 行,这些是第 0、1、2 行的“镜像副本”。第 0、1、2 行中的 A 列和 B 列是第 3、4、5 行中的 C 列和 D 列。
例如,在第 0 行中,['A', 'B', 'C', 'D'] 为 [1, 2, 3, 4]。在第 3 行中,['A', 'B', 'C', 'D'] 为 [3, 4, 1, 2]。
E 列和 F 列也是如此 --- 第 0、1、2 行中的 E 值是第 3、4、5 行中的 F 值。
我想删除这些“镜像复制”行,只留下“唯一”对。上面的正确输出应该是:
## A B C D E F
## 0 1 2 3 4 47 27
## 1 5 6 7 8 21 40
## 2 9 10 11 12 45 33
或
## A B C D E F
## 0 3 4 1 2 27 47
## 1 7 8 5 6 40 21
## 2 11 12 9 10 33 45
但不是两者——只有行的一份副本。
我不知道如何对 pandas DataFrame 进行子集化以删除这些行。如何以一种算法有效(不会导致内存爆炸)的方式做到这一点?
我的第一个想法是错误的,因为它只检查每行:
df1 = df1[~((df1.A == df1.C) & (df1.B == df1.D) & (df1.E == df1.F))]
任何帮助表示赞赏!谢谢
最佳答案
您可以执行以下操作:
from collections import Counter
import numpy as np
import pandas as pd
def key(x):
return frozenset(Counter(x).items())
df = pd.DataFrame(np.array([[1, 2, 3, 4, 47, 27], [5, 6, 7, 8, 21, 40], [9, 10, 11, 12, 45, 33],
[3, 4, 1, 2, 27, 47], [7, 8, 5, 6, 40, 21], [11, 12, 9, 10, 33, 45]]),
columns=['A', 'B', 'C', 'D', 'E', 'F'])
keys = df[['A', 'B', 'C', 'D', 'E', 'F']].apply(key, axis=1)
mask = keys.duplicated(keep='last')
print(df[mask])
输出
A B C D E F
0 1 2 3 4 47 27
1 5 6 7 8 21 40
2 9 10 11 12 45 33
这个想法是创建一个 keys
列(系列),该列在彼此镜像的那些行上具有相同的值。
这个:
def key(x):
return frozenset(Counter(x).items())
keys = df[['A', 'B', 'C', 'D', 'E', 'F']].apply(key, axis=1)
创建keys
列,然后标记重复的值:
mask = keys.duplicated(keep='last')
您还可以使用@piRSquared建议的 key :
def key(x):
a, b, c, d, e, f = x
return tuple(map(frozenset, [(a, c), (b, d), (e, f)]))
关于python - 如何删除 pandas Dataframe 中的 "mirror copy"行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58512147/