如何有条件地从pandas datafram中删除重复项

2024-10-01 09:21:38 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑以下数据帧

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项)。最终结果应该是这样的

^{pr2}$

所有高效的,一句话都是最受欢迎的


Tags: 数据importdataframepandasdfasnpnot
3条回答

还有一种选择:

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)返回以下序列:

^{pr2}$

…表达式df.isnull().any(axis=1)返回以下序列:

# 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) ]进行过滤。在

如果目标是只删除NaN副本,则需要一个稍微复杂一些的解决方案。在

首先,对AB、和{}排序,这样每个组的NaN被移到底部。然后用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

或者您可以使用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

相关问题 更多 >