Python 如何有条件地从数据帧中删除重复项
考虑以下数据帧Python 如何有条件地从数据帧中删除重复项,python,pandas,dataframe,duplicates,Python,Pandas,Dataframe,Duplicates,考虑以下数据帧 import pandas as pd df = pd.DataFrame({'A' : [1, 2, 3, 3, 4, 4, 5, 6, 7], 'B' : ['a','b','c','c','d','d','e','f','g'], 'Col_1' :[np.NaN, 'A','A', np.NaN, 'B', np.NaN, 'B', np.NaN, np.NaN],
import pandas as pd
df = pd.DataFrame({'A' : [1, 2, 3, 3, 4, 4, 5, 6, 7],
'B' : ['a','b','c','c','d','d','e','f','g'],
'Col_1' :[np.NaN, 'A','A', np.NaN, 'B', np.NaN, 'B', np.NaN, np.NaN],
'Col_2' :[2,2,3,3,3,3,4,4,5]})
df
Out[92]:
A B Col_1 Col_2
0 1 a NaN 2
1 2 b A 2
2 3 c A 3
3 3 c NaN 3
4 4 d B 3
5 4 d NaN 3
6 5 e B 4
7 6 f NaN 4
8 7 g NaN 5
我想删除与列'A''B'
相关的所有重复行。我想删除包含NaN
条目的条目(我知道对于所有Dulicate,都会有NaN
和not-NaN
条目)。最终结果应该是这样的
A B Col_1 Col_2
0 1 a NaN 2
1 2 b A 2
2 3 c A 3
4 4 d B 3
6 5 e B 4
7 6 f NaN 4
8 7 g NaN 5
所有高效的一行程序都是最受欢迎的如果目标是只删除重复的
NaN
,则需要稍微复杂一些的解决方案
首先,对A
、B
和Col_1
进行排序,这样每个组的NaN
s都会移到底部。然后用keep=first调用df.drop_duplicates
:
out = df.sort_values(['A', 'B', 'Col_1']).drop_duplicates(['A', 'B'], keep='first')
print(out)
A B Col_1 Col_2
0 1 a NaN 2
1 2 b A 2
2 3 c A 3
4 4 d B 3
6 5 e B 4
7 6 f NaN 4
8 7 g NaN 5
这里有一个替代方案:
df[~((df[['A', 'B']].duplicated(keep=False)) & (df.isnull().any(axis=1)))]
# A B Col_1 Col_2
# 0 1 a NaN 2
# 1 2 b A 2
# 2 3 c A 3
# 4 4 d B 3
# 6 5 e B 4
# 7 6 f NaN 4
# 8 7 g NaN 5
这使用按位“not”运算符~
对满足重复行(参数keep=False
导致方法对所有非唯一行求值为True)的联合条件且至少包含一个空值的行求反。因此表达式df[['A','B']].duplicated(keep=False)
返回以下序列:
# 0 False
# 1 False
# 2 True
# 3 True
# 4 True
# 5 True
# 6 False
# 7 False
# 8 False
# 0 True
# 1 False
# 2 False
# 3 True
# 4 False
# 5 True
# 6 False
# 7 True
# 8 True
…表达式df.isnull().any(axis=1)
返回以下序列:
# 0 False
# 1 False
# 2 True
# 3 True
# 4 True
# 5 True
# 6 False
# 7 False
# 8 False
# 0 True
# 1 False
# 2 False
# 3 True
# 4 False
# 5 True
# 6 False
# 7 True
# 8 True
。。。我们将这两个表达式都用括号括起来(每当在索引操作中使用多个表达式时,Pandas语法都需要这样做),然后再次将它们用括号括起来,这样我们就可以对整个表达式求反(即,~(…)
),如下所示:
~((df[['A','B']].duplicated(keep=False)) & (df.isnull().any(axis=1))) & (df['Col_2'] != 5)
# 0 True
# 1 True
# 2 True
# 3 False
# 4 True
# 5 False
# 6 True
# 7 True
# 8 False
通过进一步使用逻辑运算符&
和|
(“或”运算符),可以构建更复杂的条件。与SQL一样,根据需要使用附加括号对条件进行分组;例如,基于逻辑“条件X和条件Y均为真,或条件Z均为真”并带有df[((X)和(Y))|(Z)]
,或者您可以只使用first()
,通过使用第一个,将返回第一个notnull
值,因此原始输入的顺序实际上并不重要
df.groupby(['A','B']).first()
Out[180]:
Col_1 Col_2
A B
1 a NaN 2
2 b A 2
3 c A 3
4 d B 3
5 e B 4
6 f NaN 4
7 g NaN 5
也许:)但这能保证Col_1
的非NaN
值是保留的行吗?@mortysporty编辑。在向下投票人的辩护中,您可以选择一个示例,其中只需df.drop_duplicates
就可以给出您不想要的答案。是的。我接受否决票:)我想你需要通过keep=False
到duplicated
,这样才能起作用。@ayhan我也这么想:)嗨。如果除了我们想要摆脱的NaN
之外,还有其他价值,那么这会起作用吗?我们可以在和之后修正参数吗?@mortysporty是的,这基本上是正确的——不过,我应该警告一下,根据您测试该值的方式,如果您取消对条件的分组(即移除外圆括号),以便您可以执行类似~(df.duplicated)&(df.colu 2!=5)
的操作,这可能是最简单的。如果您直接替换df.Col_2!=5
由于两个当前条件在~(…)
中的分组方式,在上面的一行中,它将被否定(即True变为False,反之亦然)。